template <class T>class sptr{public: //parametrized constructor //this is the constructor that should be used to wrap new pointers sptr(T* new_ptr=0) { register_ptr(new_ptr); } //copy constructor sptr(const sptr& sptr) { register_ptr(sptr); } //destructor ~sptr(void) { release_ptr(); }/* There is also a bunch of accessors and overloaded operators that I didn't include.*/private: typedef std::pair<std::auto_ptr<T>, std::auto_ptr<int>> ptr_pair; typedef std::vector<ptr_pair> pair_array; //the pointer T* ptr; //its reference counter int* ref_ctr; friend class sptr; //this is the array that stores information about all pointers and their reference counters //note that all pointers are wrapped in std::auto_ptr //this is in case the sptr won't be able to release pointers due to cyclic referencing static pair_array allptrs; //the release function used to destroy the ptr as to prevent memory leaks. void release_ptr() { //if the ptr is not set, then this is an empty wrapper if(exists(ptr)) { (*ref_ctr)--; //if the ref_ctr is 0, then that is the last instance of this pointer's wrapper //so everything must be deleted if((*ref_ctr)==0) remove(ptr); //allptrs.erase(allptrs.begin()+getPtrId(ptr)); } } //the helper wrapping function that is used to automatically release the old ptr and set new one upon any change //if this function is used to wrap a completely new ptr, last param is not filled void wrap_ptr(T* new_ptr) { if(new_ptr!=ptr) { //release the old ptr before changing anything release_ptr(); //set the new one register_ptr(new_ptr); } } //this function can only be used twice outside of wrap_ptr - in the constructors void register_ptr(T* new_ptr) { if(new_ptr) { ptr=new_ptr; //if the pointer does actually exist in the allptrs array if(exists(ptr)) { ptr_pair pair=getPair(ptr); //just grab the ref_ctr from it ref_ctr=pair.second.get(); } //if the pointer is new else { //create a new ref counter ref_ctr=new int(0); //store both the ptr and the ref_ctr in the allptrs array for further use allptrs.push_back(ptr_pair(std::auto_ptr<T>(ptr), std::auto_ptr<int>(ref_ctr))); //allptrs.back().first.reset(ptr); //allptrs.back().second.reset(ref_ctr); } (*ref_ctr)++; } else { ptr=0; ref_ctr=0; } } //the find function for the sptr class bool exists(T* p) { if(p) for(pair_array::iterator it=allptrs.begin(); it!=allptrs.end(); it++) if((*it).first.get()==p) return true; return false; } void remove(T* p) { for(pair_array::iterator it=allptrs.begin(); it!=allptrs.end(); it++) if((*it).first.get()==p) { allptrs.erase(it); break; } } ptr_pair getPair(T* p) { for(pair_array::iterator it=allptrs.begin(); it!=allptrs.end(); it++) if((*it).first.get()==p) return *it; throw null_ptr_exception(); }};//initialise the static vector variabletemplate<typename T>std::vector<std::pair<std::auto_ptr<T>, std::auto_ptr<int>>> sptr<T>::allptrs=std::vector<std::pair<std::auto_ptr<T>, std::auto_ptr<int>>>();
The heap corruption is reported after leaving the scope of this function:
void ResourceMan::AddSkill(string name){ sptr<Skill> skill=sptr<Skill>(new Skill()); skill->Name=name; Skills.push_back(skill);}
Those problems began when I implemented the circular referencing functionality for my pointers. As far as I understand, heap corruption occurs when one is trying to delete an object on a different heap that it was created on. My guess is that it is triggered on release of the "name" local variable. However, I can not really see how it is linked to sptr class in any way. I'm really confused at what is happening. Is my implementation of sptr correct? Or is there something that I'm doing that I'm not supposed to do? Or is sptr even the cause of the heap corruption?