views:

149

answers:

5

Hiya.

I'm attempting to make an algorithm that can draw the entities of my isometric game in the correct order. My entities are stored in a vector of pointers.

In the drawing function I first create a new vector of the same pointers, and then start with a for-loop that loops the amount of entities that I want to have drawn. Inside that loop there is yet another loop, which determines what entity to be drawn, and when an entity is drawn it's pointer is removed from the vector using vector.erase(), so the same entity wont be drawn twice (Which is why I'm creating a copy of the vector that is containing the entity pointers).

Anyway, my code itself works, and the entities are drawn the way I want, but I appear to have a memory leak (I can actually see the memory in the Windows Task Manager climb by 28 kb/s).

The memory leak remains even if I outcomment everything except this:

vector<Entity*> list = ent_list; // ent_list is the list of entity pointers
list.clear();

So I guess I'm missing something, but I'm not sure what. I figured since I didn't use "new" the memory would be taken care of, but obviously it isn't... Hope someone can help me!

/feodor

+4  A: 

Reference for vector::clear says: "if the elements of the vector are pointers to objects, this function will not call the corresponding destructors". Are you sure you're not relying on this?

tsiki
Big if. Ask the OP if your assumption is correct. Guessing is counter productive.
Martin York
+1 Seems like a fine guess to me. As no question is ever perfectly stated, guessing is an essential part of the process. An SO answer can provide a likely answer to a vague question, and then be refined as more information emerges.
Daniel Earwicker
@Daniel Earwicker: But give the question above there could be no error at all. The OP is guessing they have a memory leak based on the output of "Task Manager" (an impossible thing to do). So this guess is trying to fix a problem that may not actually exist and thus lead to a lot of hardship to the OP as they start deleting pointers that should not be deleted. So I consider this more harmful than helpful. Note this question got the least scathing remarks as there was no attempt at actually saying delete the pointer.
Martin York
Sure, there *could* be no error - but what's most likely when someone is fooling around with raw `new` in C++ and doesn't sound very confident about it? Sherlock Holmes once famously said "It is a capital mistake to theorize before you have all the evidence; it biases the judgment." But what use would anyone be if they sat waiting for *all* the evidence? You're never going to get it! Bias, prejudice, *prior knowledge*, these are very valuable things. And an incorrect guess elicits further information.
Daniel Earwicker
Although on the specific point about Task Manager, I totally agree. Its "memory" indicator can be very misleading. If the OP uses perfmon's Private Bytes counter and sees the graph going steadily up over 10Ks of repetitions, then they have a memory leak.
Daniel Earwicker
but the OP has explictly said he isn't using new, now this may be confusion on his part but we don't know yet
jk
+1  A: 

No, standard containers only erase the memory they have created; std::list.clear(); will only invalidates and remove the iterators themselves, not the memory you have allocated.

you have to call std::list.remove() or std::list.erase() each iterator after another, and manually delete the pointers you had allocated yourself.

Stephane Rolland
or maybe use smart pointers, so that it's handled automatically.
Alexander Kjäll
No clear() as used in the OP will achieve the same thing as erase(remove()).
Martin York
It is imposable to tell if smart pointers will do anything useful. It is unclear if the list is managing resources or just holding pointers to variables that are already managed. Speculation like this is counter productive. If you can not tell what is going on ask a question in the comment section.
Martin York
+1  A: 

The vector will not delete the memory behind your pointers. You'll have to delete each Entity* before calling clear() or you could use a "smart container" as the boost::ptr_vector.

celavek
How can you even tell that the pointers need to be managed. There is not enough information to make that kind of leap.
Martin York
@Martin York I don't think I follow ... indeed the question is a little bit fuzzy but from what information the question provides it seems that he's expecting that the memory allocated for the pointers his vector contains would be deallocated by calling clear() on the vector. I'm not sure what kind of leap I'm making ...
celavek
The leap: That there is even a memory leak. If there is no memory leak then he may have pointers to stack based objects in the vector (I don;t even see any evanescent from the English prose in the question that new is being used). If you suggest using boost::ptr_vector<> now the application is likely to blow up and confuse the OP.
Martin York
A: 

The easiest way to correct this is to replace the container element with boost::shared_ptr<Element>. This will probably clean up the code that uses the vector as well and provide a pointer to better memory management standard practice down the line.

Steve Townsend
You are jumping to a conclusion with no evidence to support your theory. Rather than guessing at a solution ask the OP a question and try and confirm that this is the problem.
Martin York
Thanks Martin. My assertion is that there is enough information in the original question to indicate that the Entity* pointers are shared between two vectors. Doing a loop-and-delete before calling clear() therefore just replace a leak with a crash, when the original vector is correctly cleaned up, or perhaps that vector is not clear()-ed. Either way, the ownership of the target Entity* is unclear. boost::shared_ptr (or some alternative) addresses precisely this problem, correctly cleaning up the containers AND members when they go out of scope, regardless of how many refs to the Entity exist.
Steve Townsend
A: 

Does this fix the leak?

for (size_t i=0; i<ent_list.size(); ++i)
{
    delete ent_list[i];
}

// ok, now it's safe to call clear()
ent_list.clear();
zr
Even if it did he would not be able to tell because Task Manager does not give that kind of information.
Martin York