Skip to main content
GameDev.net gamedev.net
🔒 Locked

virtual function with smart pointer problem.

Started by ManaStone Sep 25, 2005 at 8:53 PM 7 replies 1.4k views
Original Post
ManaStone
ManaStone
Whenever I use a class with a virtual function in my smart pointer, I get a runtime error when calling the function. Could somebody tell me why this is and how I can remedy it? Here is my smart pointer class.

template <class T>
class cSmtPtr{
    T* ptr;
    cArrayList *data;
public:
	cSmtPtr()					{
								ptr=NULL;
							
								data=data->GetInstance();}
    T& operator*()              {return *ptr;}
	T& operator[](unsigned int index)				{return ptr[index];}
    T* operator->()             {return ptr;}
	void  operator=(cSmtPtr<T> &temp)
	{
		
		ptr= &(*temp);
	
	}


	void New(GLint iSize=1)
	{
		ptr=(T*)data->New(sizeof(T)*iSize);

	}
	void Delete()
	{
	 data->Delete(ptr);
	 ptr=NULL;

	}

	bool Check()
	{
		return data->CheckPointer(ptr);
	}
	void operator=(T* temp)       {ptr=temp;}
	

};





My program

class cBlah{

private:
	int x;
public:
	virtual void print()
	{
		cout<<"first"<<endl;

	}

};


void main()
{

	cSmtPtr<cBlah> b;
	
	b.New();

	b->print();
	
} 


-----------------------------Download my real time 3D RPG.
SiCrane
SiCrane
What does the cArrayList class look like?
Sneftel
Sneftel
I'm guessing the problem is somewhere in the New method. Unfortunately, you haven't posted the full smart pointer implementation, so it's difficult to tell.

On a related note: Are you seriously considering writing a smart pointer class that actually doubles as a smart array class? And using it with virtual classes? That seems like all kinds of a bad idea.
ManaStone
ManaStone
Should that matter much? It is basically a singleton class that allocates data with byte guards in front and behind the dynamic array to check to see if it has been overwritten.

Header:
class cArrayList{	//--------------------NODE STRUCTURE---------------------------	struct sNode{void		*ptr;GLushort	siSize;sNode		*next;sNode		*prev;};//-------------------------------------------------------------private:	 sNode *mHead;	 sNode *mTail;	 GLint miNumElements;	 	 static int ival;	public:	cArrayList();	 void* New(GLint iSize);	 void Delete(void* ptr);	 bool CheckPointer(void* ptr);	 bool CheckAllPointers();	 GLint CountElments();	 GLint GetNumElements(){ return miNumElements;}	 cArrayList* GetInstance()	{		 static cArrayList pInstance;		 return &pInstance	}};


implementation:
void* cArrayList::New(GLint iSize){#if _DEBUG_ == 1	//allocate the memory	void *ptr=malloc(iSize + 2*sizeof(GLushort) + sizeof(sNode*));	//if the pointer failed to allocate, then return NULL.	if(ptr==NULL)		return NULL;		//allocate memory for the node;	sNode *node=new sNode;			// if the node failed to load then delete ptr and return NULL	if(node==NULL)	{		delete[] ptr;		return NULL;	}	//Load a the magic number in back of the array	GLushort *psiArray =(GLushort*) ptr;	psiArray[0]= MAGIC_NUMBER;		//Add in the node pointer in back of the array	sNode **nodePtr;	nodePtr=(sNode**) &psiArray[1];	nodePtr[0]=node;	//Load the magic number in back of the array	GLubyte	*byteArray=(GLubyte*)  &nodePtr[1];	psiArray		  =(GLushort*) &byteArray[iSize];	psiArray[0]=MAGIC_NUMBER;	//set up values for sNode;	node->next=NULL;	node->ptr= (void*)byteArray;	node->siSize=iSize;	//add the node to the tail	mTail->next=node;	node->prev=mTail;	mTail=node;		//increment the number of elements	miNumElements++;		return node->ptr;#endif	return malloc(iSize);}/**@par Description:Deletes allocated memory@param ptr - a pointer to memory allocated by this class. */void cArrayList::Delete(void (*ptr)){#if _DEBUG_ == 1	sNode   *ptrNode;	GLubyte *byteArray=(GLubyte*) ptr;		//find the pointer node.	memcpy(&ptrNode,&byteArray[-(sizeof(sNode*))],sizeof(sNode*));	//remove the pointer node from the list		ptrNode->prev->next=ptrNode->next;		if(ptrNode!=mTail)		ptrNode->next->prev=ptrNode->prev;	else		mTail=ptrNode->prev;		//delete the pointer node	delete ptrNode;		//Delete the array;	free(&byteArray[-(sizeof(sNode*)+sizeof(GLushort))]);	//decrement the number of arrays.	miNumElements--;#endif	delete ptr;}/**@par Description:Checks to see if all the memory blocks allocated by this class are valid.@return - returns true if all of the memory blocks are valid; otherwise, returns true.  */ bool cArrayList::CheckAllPointers(){	 #if _DEBUG_ == 1	  sNode *temp=mHead->next;	 while(temp!=NULL)	 {		if(CheckPointer(temp->ptr)==false)			return false;		temp=temp->next;	 }	#endif	return true;}/** @par Description:  Checks to see if a memory block allocated by this class is valid.  @param ptr   - This is the pointer to the memory allocated by this class.    @return - Returns false if ptr is NULL or returns false if something is wrong with the memory block;Otherwise, returns true. */ bool cArrayList::CheckPointer(void *ptr){	if(ptr==NULL)		return false;	sNode		*ptrNode;	GLubyte		*byteArray=(GLubyte*) ptr;	GLushort	*psiArray;		//find the pointer node.	memcpy(&ptrNode,&byteArray[-(sizeof(sNode*))],sizeof(sNode*));	//find the magic number	psiArray=(GLushort*) &byteArray[-(sizeof(sNode*)+sizeof(GLushort))];	//if the first guard doesn't equal the magic number, return false;	if(psiArray[0]!=MAGIC_NUMBER)		return false;		//let psiArray point to the last guard. 	psiArray=(GLushort*) &byteArray[ptrNode->siSize];	//if the second guard doesn't equal the magic number, return false;	if(psiArray[0]!=MAGIC_NUMBER)		return false;	//delete the pointer node	return true;} cArrayList::cArrayList(){	 mHead= new sNode;	 mHead->next=NULL;	 mHead->prev=NULL;	 mTail= mHead;	 	 miNumElements=0;}/** @par Description:  Counts the the number of memory blocks in this class.    @return - Returns how many memory blocks are in this class.*/GLint cArrayList::CountElments(){	GLint iNum=0;	sNode *temp=mHead->next;	while(temp!=NULL)	{		temp=temp->next;		iNum++;	}	return iNum;}



-----------------------------Download my real time 3D RPG.
ManaStone
ManaStone
Ok, it appears as if it is the byte guards that are causing the problems with the virtual function. It doesn't have any problems using regular functions. What is special about virtual functions.


EDIT: actually it appears to be a problem not with the byte guards, but using malloc().

[Edited by - ManaStone on September 25, 2005 9:13:04 PM]
-----------------------------Download my real time 3D RPG.
ManaStone
ManaStone
Quote:
Original post by Sneftel
I'm guessing the problem is somewhere in the New method. Unfortunately, you haven't posted the full smart pointer implementation, so it's difficult to tell.

On a related note: Are you seriously considering writing a smart pointer class that actually doubles as a smart array class? And using it with virtual classes? That seems like all kinds of a bad idea.


Actually that was all of the smart pointer implementation. I decided to make everything inline.

Why is that a bad idea? I wanted to make a pointer in which the user wouldn’t have too much trouble allocating memory too it as well as being able to check to see if the memory has been overwritten.
-----------------------------Download my real time 3D RPG.
snk_kid
snk_kid
Quote:
Original post by ManaStone
Ok, it appears as if it is the byte guards that are causing the problems with the virtual function. It doesn't have any problems using regular functions. What is special about virtual functions.


EDIT: actually it appears to be a problem not with the byte guards, but using malloc().


Yes your code is absolutely fudged, unless you know exactly what you are doing you shouldn't be using C memory rountines directly in C++. The C memory rountines deal with uninitialized memory, malloc/free only allocate/deallocate uninitialized memory operators new/delete allocate/deallocate AND construct/destroy meaning after allocation the constructor is invoked automatically and before deallocation the destructor is invoked automatically. Also mixing calls to malloc/free and new/delete is really bad.

When you are dealing with polymorphic types (a type which has at least one (pure) virtual member function) additional set-up/destroy code is done that deals with things like setting up the vtable. This is does not happen with C memory rountines and if you must seperate allocation/deallocation from construction/destruction then you must use the placement new operator for NON POD-types (POD == Plain Old Datatype a technical term used in the C++ standard), placement new's sole purpose is to invoke constructors and before you deallocate memory you must explicitly invoke the destructor yourself.

When you have an array of NON-POD type you cannot use memcpy either as it will mess alot of things up like the vptr.

Now why are you writing a custom list type when the C++ standard library already provides a list type (called std::list and something between a dynamic array and list called std::deque), all standard library containers are also parameterized by allocator type so you can provide custom memory models/schemes to them like boost::fast_pool_allocator.

[Edited by - snk_kid on September 26, 2005 4:32:52 AM]
ManaStone
ManaStone
Quote:
Original post by snk_kid
Quote:
Original post by ManaStone
Ok, it appears as if it is the byte guards that are causing the problems with the virtual function. It doesn't have any problems using regular functions. What is special about virtual functions.


EDIT: actually it appears to be a problem not with the byte guards, but using malloc().


Yes your code is absolutely fudged, unless you know exactly what you are doing you shouldn't be using C memory rountines directly in C++. The C memory rountines deal with uninitialized memory, malloc/free only allocate/deallocate uninitialized memory operators new/delete allocate/deallocate AND construct/destroy meaning after allocation the constructor is invoked automatically and before deallocation the destructor is invoked automatically. Also mixing calls to malloc/free and new/delete is really bad.

When you are dealing with polymorphic types (a type which has at least one (pure) virtual member function) additional set-up/destroy code is done that deals with things like setting up the vtable. This is does not happen with C memory rountines and if you must seperate allocation/deallocation from construction/destruction then you must use the placement new operator for NON POD-types (POD == Plain Old Datatype a technical term used in the C++ standard), placement new's sole purpose is to invoke constructors and before you deallocate memory you must explicitly invoke the destructor yourself.

When you have an array of NON-POD type you cannot use memcpy either as it will mess alot of things up like the vptr.

Now why are you writing a custom list type when the C++ standard library already provides a list type (called std::list and something between a dynamic array and list called std::deque), all standard library containers are also parameterized by allocator type so you can provide custom memory models/schemes to them like boost::fast_pool_allocator.


Thank you, that was very informative. Do lists or anything else in STL provide a way to allocate memory with guards that can be check around the memory?
-----------------------------Download my real time 3D RPG.
Matt Green
Matt Green
Quote:
Thank you, that was very informative. Do lists or anything else in STL provide a way to allocate memory with guards that can be check around the memory?

No. Your C runtime library should be able to do this, however.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.