views:

65

answers:

2

Hi.

I'm working on a game engine and in an earlier question it was suggested that I start using boost::ptr_vector to maintain a list of pointers.

The basic idea is to have several State's, each State has a SceneGraph. Each state has several resources that they initialize, and then stuff its own SceneGraph. The SceneGraph has a boost::ptr_vector that it stuffs the resource pointers in.

Here's the relevant code:

Resource creation and addition to the SceneGraph in TestState

backgroundImage = new DEBUG_NEW Fenris::Node2D::Image(std::string("backgroundImage"), std::string("../media/img/background.jpg"));
sceneGraph->addNode(backgroundImage, Fenris::Core::STRATUM_BACK);

SceneGraph

boost::ptr_vector<SceneGraphNode> backStratumList;
// The add() method
void addNode(SceneGraphNode *pNode, STRATUM_TYPE stratumType) { switch(stratumType) { case STRATUM_BACK: backStratumList.push_back(pNode); break; case STRATUM_NORMAL: normalStratumList.push_back(pNode); break; case STRATUM_FOREGROUND: foregroundStratumList.push_back(pNode); break; } }

Edited main.cpp with relevant lines

PlatformGame::State::TestState *testState = new DEBUG_NEW PlatformGame::State::TestState(std::string("testState"));
// Clean up the previously registered state (deletes its sceneGraph -- verified that the destructor is in fact called via debugger) delete testState;
// Dump memleak report if we're running in debug mode #ifdef _DEBUG _CrtDumpMemoryLeaks(); #endif

I'm using _CrtDumpMemoryLeaks() to output a memory leak log report. The log report tells me I have a memory leak;

Detected memory leaks!
Dumping objects ->
{174} normal block at 0x00A56630, 32 bytes long.
 Data: <../media/img/bac> 2E 2E 2F 6D 65 64 69 61 2F 69 6D 67 2F 62 61 63 
{173} normal block at 0x00A565A0, 8 bytes long.
 Data: < c      > A8 63 A5 00 00 00 00 00 
Object dump complete.

Is _CrtDumpMemoryLeaks() having trouble with boost::ptr_vector or have I done something wrong? The debugger tells me that State does invoke its destructor (which has; delete sceneGraph) and I've also verified that the SceneGraph's destructor is also invoked.

Any help is greatly appreciated, I'd love to see an empty memory leak report :-)

A: 

A few possibilities:

  • Your Node2D::Image class has string/char pointers and does not delete the strings/char buffer it is pointing to.

  • Your switch case in the AddNode method is missing a default. It is possible that you lose any reference to pNode!

  • The type is SceneGraphNode in the boost::ptr_vector but you insert Image which I presume is a subclass. Is the destructor virtual?

I would suggest you try putting a breakpoint in the Image class destructor and see if that is called.

(Caveat: been a while since I did C++!)

Moron
+2  A: 

It sure doesn't look like a vector you're leaking. Note that the string is readable, that's at least one hint.

If you can get the number between the curly braces stable ("{173}") then you can get a breakpoint when the memory is allocated. Put this in your main() function:

_crtBreakAlloc = 173;

Use #include <crtdbg.h> if necessary. Repeat for 174 to find the other one.

Hans Passant
+1 for the breakAlloc tip, but it might not actually help pinpoint the cause of the leak.
Moron
Nah, it is unbeatable, breaks right at the source code location where the allocation takes place. Iff the number is consistent. Not that hard to do, the program has to allocate memory in the same order when it runs again.
Hans Passant
I know that I'm not leaking a vector, but if I haven't misunderstood boost::ptr_vector, ptr_vector takes ownership of pointers added to the vector and deletes them when the ptr_vector is destructed along with the class that contains the ptr_vector. I'll definitely give breakAlloc a go.
John
@Hans: Yes, but the actual fix might be elsewhere (like a missing delete in some class which contains the 'culprit' class). That is what I meant by my above statement.
Moron
@John: I am curious. Did you figure out the cause of the leak?
Moron
@Moron: I haven't figured it out yet. It might be because I'm not too experienced with debugging and I'm not that experienced with C++ yet.The destructor of the SceneGraph is in fact invoked. By debugging and stepping in to delete, I end up in the std::string destructor (there's a std::string in the SceneGraphNode which is contained in the SceneGraph's boost::ptr_vector).Worst case I'll go back to using plain naked pointers in a std::vector and use delete manually.
John
Just to clear it up -- when I skip using a boost::ptr_vector in the SceneGraph and manually delete the resource that is added to the SceneGraph's ptr_vector I do not get a memory leak.
John