Jump to content
  • Advertisement
Sign in to follow this  

Virtual Method issues... [solved]

This topic is 4720 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

As some of you may know, I am working on an object factory that uses free lists. Anyway, everything was done, etcetera, and I decided to try to write another type of freelist that would help prevent cache missing. Anyway, everything seems fine and dandy...except all of a sudden I get an error whenever my methods hit a virtual method... The output is: "FreeListTest has exited due to signal 10 (SIGBUS)." (FreeListTest is the name of the program). And it ONLY crashes when they are virtual...if I take away the virtual keyword, it runs fine. Except I know that the virtual methods are fine because it works with my other freelist, which uses std::list. Anyway, does anyone know why I might be running into trouble with this. Below is the code to the new form of the free list. Maybe it will help.
/*
 *  MemoryProtectedFreeList.h
 *  Aurora Engine
 *
 *  Created by Corey Hoffstein on 6/18/05.
 *  Copyright 2005. All rights reserved.
 *
 */

#ifndef __MEMORYPROTECTEDFREELIST_H__
#define __MEMORYPROTECTEDFREELIST_H__

#include "Logger.h"
#include "FreeList.h"

template <class U> 
class MemoryProtectedFreeList : public FreeList<U>
{
	private:
		string className;
		int InitialSize;
		int CurrentSize;
		
		U *objectList; //stores the actual objects
		U **freeList; //stores the current free objects
		int pointer; //the pointer to the next free object
		
	public:
		MemoryProtectedFreeList(int iInitialSize, string iClassName)
		{
			objectList = NULL;
			freeList = NULL;
			InitialSize = iInitialSize;
			CurrentSize = InitialSize;
			className = iClassName;
			
			LOG(mainLog, Logger::INFO, "Creating free list with InitialSize: " << iInitialSize);
		   
			objectList = (U*)malloc(iInitialSize * sizeof(U));
			if(objectList == NULL)
			{
				LOG(mainLog, Logger::ERROR, "Could not realloc MemoryProtectedFreeList objectList for class " << className << " of size: " << InitialSize);
			}
			
			freeList = (U**)malloc(iInitialSize * sizeof(U*));
			if(freeList == NULL)
			{
				LOG(mainLog, Logger::ERROR, "Could not realloc MemoryProtectedFreeList freeList for class " << className << " of size: " << InitialSize);
			}	
			for(int i = 0; i < iInitialSize; ++i)
				freeList = &objectList;
			
			pointer = iInitialSize-1; //points to the top object
		}
		
		~MemoryProtectedFreeList()
		{
			FreeAll();
		}		
		
		inline U* getInstance()
		{
			cleanMemory();
			
			//make sure we have one.  Otherwise, create a new one
			if(pointer >= 0)
			{
				return freeList[pointer--];
			}
			
			//well, we didn't have any, so we should reinitialize the list, because we obviously underestimated how many we needed
			else
			{
				LOG(mainLog, Logger::INFO, "Resizing FreeList of class " << className << " to add " << InitialSize /2 + 1 << " nodes.");
				//we should add to the list half + 1 of our original size
				objectList = (U*)realloc(objectList, sizeof(U)*(CurrentSize + InitialSize/2 + 1));
				if(objectList == NULL)
				{
					LOG(mainLog, Logger::ERROR, "Could not realloc MemoryProtectedFreeList objectList for class " << className << " of size: " << InitialSize);
				}
				
				freeList = (U**)realloc(objectList, sizeof(U)*(CurrentSize + InitialSize/2 + 1));
				
				if(freeList == NULL)
				{
					LOG(mainLog, Logger::ERROR, "Could not realloc MemoryProtectedFreeList freeList for class " << className << " of size: " << InitialSize);
				}
				for(int i = 0; i < InitialSize / 2 + 1; ++i)
					freeList = &objectList[CurrentSize + i]; //remember, current size is still the OLD size -- it hasn't been updated yet
				
				pointer = InitialSize / 2;
				CurrentSize += InitialSize / 2 + 1;
				
				return freeList[pointer--];
			}
		}
		
		inline void FreeInstance(U *pInstance)
		{	
			if(pointer < CurrentSize)
			{
				freeList[++pointer] = pInstance;
			}
			else
			{
				LOG(mainLog, Logger::ERROR, "Trying to add instance of " << className << " to list that is full?");
			}
		}
		
		inline void cleanMemory()
		{
			/* We don't clean memory with static arrays */
		}
		
		inline void FreeAll()
		{
			LOG(mainLog, Logger::INFO, "Deleting FreeList for class: " << className << " containing " << pointer << " nodes.");
			if(pointer < CurrentSize)
			{
				LOG(mainLog, Logger::ERROR, "MEMORY LEAK: FreeList of class " << className << " is missing " << CurrentSize - pointer << " node" << (CurrentSize - pointer > 1 ? "s." : ".") );
			}
			
			if(objectList)
				delete [] objectList;
			if(freeList)
				delete [] freeList;
		}
};

#endif




My logs tell me everything is resizing correctly, and my debugger says that each variable instanced from these freelists is unique...so I don't think its an issue running out of memory or anything like that. Any thoughts? I really have no idea what is going on. Thanks [Edited by - visage on June 19, 2005 2:35:47 PM]

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by visage
Anyway, everything seems fine and dandy...except all of a sudden I get an error whenever my methods hit a virtual method...
Anyway, does anyone know why I might be running into trouble with this.


After very briefly looking at your code, it appears that the problem is that you never actually construct your objects. You allocate memory for them, sure. But you never construct them. Since the constructor is never called, your v-table is gonna be junk.

As a side note, it looks like you use malloc/realloc to allocate your memory and then use delete[] to free that memory. Don't do that! That's bad. You need to be careful to match those up properly malloc/free or new/delete.

So, as I see it, you can fix this in one of two ways:

1. Use new instead of malloc/realloc.
2. Use malloc/realloc and then loop through your list of objects and use "placement new" to construct them. Then, when you go to get rid of them, you'll need to loop through them and manually call the destructor. And then finally, use free() to clean up the memory.

Hope that helps!

-John

Share this post


Link to post
Share on other sites
Oh, one more thing. If you go the manual construction route then realloc could get a bit messy. The problem being that you probably don't want to re-initialize all of the objects, just the new ones. So, I suppose you'd have to handle that somehow.

-John

Share this post


Link to post
Share on other sites
Well, the free() thing was glaring me in the face.
I tried the placement new method, but it still didn't work. I had to change the arrays a little to implement it, but maybe you can still help me out with this:


/*
* MemoryProtectedFreeList.h
* Aurora Engine
*
* Created by Corey Hoffstein on 6/18/05.
* Copyright 2005 __MyCompanyName__. All rights reserved.
*
*/


#ifndef __MEMORYPROTECTEDFREELIST_H__
#define __MEMORYPROTECTEDFREELIST_H__

#include "Logger.h"
#include "FreeList.h"

template <class U>
class MemoryProtectedFreeList : public FreeList<U>
{
private:
string className;
int InitialSize;
int CurrentSize;

U **objectList; //stores the actual objects
U **freeList; //stores the current free objects
int pointer; //the pointer to the next free object

public:
MemoryProtectedFreeList(int iInitialSize, string iClassName)
{
objectList = NULL;
freeList = NULL;
InitialSize = iInitialSize;
CurrentSize = InitialSize;
className = iClassName;

LOG(mainLog, Logger::INFO, "Creating free list with InitialSize: " << iInitialSize);

objectList = (U**)malloc(iInitialSize * sizeof(U));
if(objectList == NULL)
{
LOG(mainLog, Logger::ERROR, "Could not realloc MemoryProtectedFreeList objectList for class " << className << " of size: " << InitialSize);
}
//use placement new to create the objects
for(int i = 0; i < iInitialSize; ++i)
objectList = new (objectList) U;

freeList = (U**)malloc(iInitialSize * sizeof(U*));
if(freeList == NULL)
{
LOG(mainLog, Logger::ERROR, "Could not realloc MemoryProtectedFreeList freeList for class " << className << " of size: " << InitialSize);
}
for(int i = 0; i < iInitialSize; ++i)
{
freeList = objectList;
}

pointer = iInitialSize-1; //points to the top object
}

~MemoryProtectedFreeList()
{
FreeAll();
}

inline U* getInstance()
{
cleanMemory();

//make sure we have one. Otherwise, create a new one
if(pointer >= 0)
{
cout << "Pointer currently at: " << pointer << " for class " << className << endl;
return freeList[pointer--];
}

//well, we didn't have any, so we should reinitialize the list, because we obviously underestimated how many we needed
else
{
cout << "Resizing pointer info for class " << className << endl;
LOG(mainLog, Logger::INFO, "Resizing FreeList of class " << className << " to add " << InitialSize /2 + 1 << " nodes.");
//we should add to the list half + 1 of our original size
objectList = (U**)realloc(objectList, sizeof(U)*(CurrentSize + InitialSize/2 + 1));
if(objectList == NULL)
{
LOG(mainLog, Logger::ERROR, "Could not realloc MemoryProtectedFreeList objectList for class " << className << " of size: " << InitialSize);
}

freeList = (U**)realloc(objectList, sizeof(U)*(CurrentSize + InitialSize/2 + 1));
if(freeList == NULL)
{
LOG(mainLog, Logger::ERROR, "Could not realloc MemoryProtectedFreeList freeList for class " << className << " of size: " << InitialSize);
}

for(int i = 0; i < InitialSize / 2 + 1; ++i)
freeList = objectList[CurrentSize + i]; //remember, current size is still the OLD size -- it hasn't been updated yet

pointer = InitialSize / 2;
CurrentSize += InitialSize / 2 + 1;

cout << "After resize, pointer currently at: " << pointer << " for class " << className << endl;
return freeList[pointer--];
}
}

inline void FreeInstance(U *pInstance)
{
if(pointer < CurrentSize)
{
freeList[++pointer] = pInstance;
}
else
{
LOG(mainLog, Logger::ERROR, "Trying to add instance of " << className << " to list that is full?");
}
}

inline void cleanMemory()
{
/*
//we have too many in the bank. We should free up some space
//this may occur in a situation where the freelist was initialized
//too small, and too many instances were called and stayed alive -- but suddenly
//all were freed at once, creating a great abundance. This couple probably
//happen with something like particles
if(pointer > InitialSize)
{
int dif = pointer - InitialSize;
LOG(mainLog, Logger::INFO, "Resizing FreeList of class " << className << " to remove " << dif << " nodes.");


Fuck, I have no idea how to handle this one. The issue is that the freelist is entire unsorted, so while
we can realloc to knock off however many in the objectList, we will have to _search_ through the freelist,
which, if you ask me, just isn't worth it.

CurrentSize -= dif;
}
*/

}

inline void FreeAll()
{
LOG(mainLog, Logger::INFO, "Deleting FreeList for class: " << className << " containing " << pointer << " nodes.");
if(pointer < CurrentSize)
{
LOG(mainLog, Logger::ERROR, "MEMORY LEAK: FreeList of class " << className << " is missing " << CurrentSize - pointer << " node" << (CurrentSize - pointer > 1 ? "s." : ".") );
}

if(objectList)
{
for(int i = 0; i < CurrentSize; ++i)
delete objectList;
free(objectList);
}
if(freeList)
free(freeList);
}
};

#endif






Same exact error...

Thanks for the help so far mate.


EDIT: A thought...is this happening because the template U inherits from other classes, but sizeof() doesn't take that into account in the malloc, and therefore doesn't actually allocate enough space...?

The reason I am using malloc, realloc, and free is because I didn't want to waste my time having to copy over info...but would new, memcpy, and delete be just as effective? It would probably require more temporary arrays...but it may work. Any other thoughts on how to do this?

Share this post


Link to post
Share on other sites
You bumped after 3 hours?! Come on, man, just give it a chance!

Anyway, it looks like your placement new usage is wrong.

//use placement new to create the objects
for(int i = 0; i < iInitialSize; ++i)
objectList = new (objectList) U;


will just keep reinitializing objects over the first entry in objectList.
You need something more like:

for(int i = 0; i < iInitialSize; ++i)
objectList = new (&objectList) U;


Did you step through with a debugger to look if the vtable is initialized?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Haha, yeah, I am wayyyy impatient ;)
Anyway, I made your fix (thanks for the info -- first time I had even heard about placement new...)

Unfortunately, it didn't work.

And I don't know how to tell if the vtable is initialized...but something isn't sitting right with me and the code anyway. I can't quite put my finger on it...
Thoughts?

Thanks for the help!

Share this post


Link to post
Share on other sites
Quote:
Original post by Visage
And I don't know how to tell if the vtable is initialized...


If you are using a Microsoft IDE, then set a breakpoint on the variable sometime after it is supposedly 'constructed' and go to the locals/autos tab in the debugger. Expand the tree for the variable and you should see the vtable variable. It should have an address as well as expand with more functions that all have addresses as well. Note the name is like __vfptr or something like that.

Share this post


Link to post
Share on other sites
Well, I am using XCode, which uses GDB (I am pretty sure). However, when looking at the arrays, it looks like only 1 object exists, and I see no mention of any sort of vtable...

Share this post


Link to post
Share on other sites
Quote:
Original post by visage
objectList = (U**)malloc(iInitialSize * sizeof(U));


I think this is wrong. It should be U*, not U**, shouldn't it?

EDIT: Your realloc is wrong in the same way. Also, at the end, you loop through and "delete" your objects. You shouldn't call delete on them. Instead, call the destructor explicity( ex. objectList.~objectList() ) and then just free the memory

-John

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!