auto_ptr triggers heap corruption when deleting std::string

Started by
2 comments, last by CzarKirk 13 years, 5 months ago
Hello. I'm trying to implement my own smart pointer class for learning purposes. As a solution to circular referencing, I made a static array that holds all pointers wrapped in std::auto_ptr, which releases the pointers that still exist on application exiting. However, that doesn't work and triggers a heap corruption error. Here is the code I think is relevant:
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?
Advertisement
Heap corruption occurs when the bookkeeping structures for dynamic memory get corrupted. It can happen when freeing memory in the wrong heap, freeing memory twice, freeing memory that wasn't actually allocated, writing past the end of allocated memory, writing before the beginning of allocated memory, writing to freed memory or any number of other reasons involving bad pointer use.

That said, storing std::auto_ptrs in a std::vector is undefined behavior. I'm actually pretty surprised that your code even compiles.
I see. Thank you for clarifying that. However, is there a way for me to implement sptr with circular references without using auto_ptrs? I want my allptrs array to automatically clean its contents up upon its deletion. This way any circular referencing will die upon program exiting.
Wrap the array in a class/structure, and in the destructor iterate through the array deleting stuff.

This topic is closed to new replies.

Advertisement