dynamic memory and vectors

hi

i was having lots of memory leaks due to not being able to delete allocated memory. i worked around and there are no more leaks, – checked with xcode’s MallocDebug, just the standard 64 bytes – but was wondering why this is happening, and if there are proper ways to do this.

my program generates a lot of ‘explosions’ which allocate random numverts and are present for some time and then i free them. the explosions go inside a std::vector, when the explosions life is zero i remove the explosions from the vector.

the problem i faced was not being able to delete the allocated pointer in the destructor. which is really weird… the program crashes and points to the destructor line if i try to deallocate the pointer in the destructor, with crashes like: openFrameworksDebug(5565,0xa06d0720) malloc: *** error for object 0x87d800: double free
*** set a breakpoint in malloc_error_break to debug

it doesnt crash and runs with no leaks it i setup a func to deallocate the memory, leaving an empty destructor.

is this normal vector behaviour? if the parts are not in a vector, calling the destructor seems safe, but if i try to destroy the part from the vector, this kinds of crashes come in…

what should be proper code to handle this kinds of situations?

here is some simplified example code that shows this problem

testApp.h

  
  
#ifndef _TEST_APP  
#define _TEST_APP  
  
  
#include "ofMain.h"  
#include "ofxVec3f.h"  
  
class Explosion{  
public:	  
	ofxVec3f *verts;  
	int numverts;  
	int life;  
	  
	Explosion(){  
		life = 255;  
		numverts = ofRandom(10,100);  
		verts = new ofxVec3f[numverts];  
		for(int i=0;i<numverts;i++){  
			float a = 100;  
			verts[i].set(ofRandomuf()*a,ofRandomuf()*a,ofRandomuf()*a);  
		}				  
	}  
	  
	~Explosion(){  
		//if(verts!=NULL) delete[] verts; // crashes  
	}  
	void clear(){  
		if(verts!=NULL) delete[] verts; // doesnt crash and doesnt leak  
	}  
	void update(){  
		life--;	  
	}  
	void render(){  
		glColor4f(1, 1, 1, life/255.f);  
		for(int i=0;i<numverts-1;i++){  
			ofLine(verts[i].x, verts[i].y, verts[i+1].x, verts[i+1].y)	;  
		}  
	}  
	  
};  
  
  
class ExplosionManager{  
public:  
	vector <Explosion> myparts;  
	ExplosionManager(){;}  
	~ExplosionManager(){myparts.clear();}  
	void update(){  
		for(int i=0; i<myparts.size(); i++){  
			myparts[i].update();  
			if(myparts[i].life<0){  
			//	myparts[i].~Explosion();//also crashes  
				myparts[i].clear(); //deletes allocated memory and runs smooth  
				myparts.erase(myparts.begin()+i,myparts.begin()+i+1);  
			}  
		}  
	}  
	void add(){  
		Explosion p;  
		myparts.push_back(p);  
	}  
	void render(){  
		for(int i=0; i< myparts.size(); i++){			  
			myparts[i].render();  
		}	 	  
	}  
};  
  
  
class testApp : public ofBaseApp{  
  
	public:  
		void setup();  
		void update();  
		void draw();  
  
		void keyPressed  (int key);  
		void keyReleased(int key);  
		void mouseMoved(int x, int y );  
		void mouseDragged(int x, int y, int button);  
		void mousePressed(int x, int y, int button);  
		void mouseReleased(int x, int y, int button);  
		void windowResized(int w, int h);  
  
	Explosion one;  
	ExplosionManager manager;  
	  
};  
  
#endif  
  
  
  

testApp.cpp

  
  
#include "testApp.h"  
  
//--------------------------------------------------------------  
void testApp::setup(){  
	ofEnableAlphaBlending();  
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
	manager.update();  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	one.render();  
	manager.render();  
}  
  
//--------------------------------------------------------------  
void testApp::keyPressed(int key){  
	if(key=='a')  
		manager.add();  
}  
  
//--------------------------------------------------------------  
void testApp::keyReleased(int key){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mouseMoved(int x, int y ){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mouseDragged(int x, int y, int button){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mousePressed(int x, int y, int button){  
	manager.add();  
}  
  
//--------------------------------------------------------------  
void testApp::mouseReleased(int x, int y, int button){  
  
}  
  
//--------------------------------------------------------------  
void testApp::windowResized(int w, int h){  
  
}  
  
  
  

thank you!

a

I could be wrong, but I don’t think you can do this properly to a vector and that may be the source of your problems:

  
  
for(int i=0; i<myparts.size(); i++){  
         if(myparts[i].life<0){  
         myparts.erase(myparts.begin()+i,myparts.begin()+i+1);  
         }  
      }  
  

since erase alters the for loop in the middle of the for loop.

deleting from the middle of a vector, there are a few approaches – I typically use the remove_if idiom which regroups the objects based on a boolean function and erase removes them. it’s one line of code and very clean:

erase(remove_if(…));

is one of the more easy approaches. you can keep your for loop which clears any dead explosions then run remove_if to delete them safely from the vector.

another approach is to use an iterator (note this is written by hand, in the morning, pre coffee so no guarantees it will work as is):

  
  
vector<explosion>::iterator iter =  explosions.begin();  
while (iter != explosions.end())  
{  
  
    if(iter->life == 0)  
    {  
        iter->clear();  
        // erase returns the new iterator  
        iter = explosions.erase(iter);  
    }  
    else  
    {  
        ++iter;  
    }  
}  

I know that looks funky, but it goes through the list backwards.

this is helpful:

http://stackoverflow.com/questions/1604-…-ms-as-i-go

and

http://en.wikipedia.org/wiki/Erase-remove-idiom

hope that helps,
zach

as far as memory management goes, you should never, ever call the destructor directly:

myparts[i].~Explosion(); <— BAD!

the destructor ~Explosion will be called when the vector cleans up the memory from its erase() call. (this is true because you have a vector of Explosion objects - if you had a vector of Explosion* pointers you would need to manually say delete myparts[i].)

otherwise, Zach is correct that you can’t call erase() from inside a loop as it will modify the index values for the existing elements, and can break iterators or pointer references.

zach, thanks for the heads up and the links. the 2 methods you suggest are easy to grasp and run nicely(your pre-morning code is perfect:). erasing from a vector alters it, so the indices no longer point well, and i should keep a good pointer/iterator to the elements.

but the same crash/error i was having before pops up if i try to deallocate the memory in the destructor, using iterators or remove_if (xcode says the same error: double free of object at adress)

this is what is not clear :

why can’t i deallocate the memory in the destructor when erasing an element from the vector?

when the vector erases an element, first it calls its destructor and then removes from memory.
why do i have to put a ‘clear’ function, called before i erase the part from the vector which deallocates the memory? shouldnt this be a job for the destructor?

@damian, this was why i was trying to call directly the destructor, i knew i shouldnt, i was explicitly trying to deallocate the memory using the destructor instead of the clear function

short fixes for a good hump of code, happy that a big project is running smoothly with 0 leaks:)

you should be able to erase the memory in the destructor, and everything should work.

the vector.erase() call will destroy your Explosion instance, which means the destructor will get called. no need for a clear() function.

looking more closely, there’s a problem with your original erase call:

  
myparts.erase(myparts.begin()+i,myparts.begin()+i+1);  

this will actually erase myparts[i] AND myparts[i+1]. it should be just

  
myparts.erase(myparts.begin()+i);  

another technique, similar to zach’s but keeping the array access paradigm, is to subtract one from i after erasing. like this:

  
  
      for(int i=0; i<myparts.size(); i++){  
         myparts[i].update();  
         if(myparts[i].life<0){  
            myparts.erase(myparts.begin()+i); // fixed this erase call  
            i--; // new code to keep i index valid  
         }  
      }  
  

[quote author=“damian”]you should be able to erase the memory in the destructor, and everything should work.

the vector.erase() call will destroy your Explosion instance, which means the destructor will get called. no need for a clear() function.
[/quote]

this was what i was hoping for. i rechecked the code again and again, but always get a crash the moment i try to delete the explosion from the vector if the deallocation happens in the destructor…

if i deallocate the memory before erasing the part with the clear function, all works well

this is really annoying, sorry, must be an error somewhere and can’t track it… and this is happening in a lot of classes in a bigger project, which i worked around with this clear thingie…

can you run the project i attach without crashes? [attachment=0:19dx63uo]dynmem+vector2.zip[/attachment:19dx63uo]
if you add parts, with mousepressed, it will crash when the particle is removed from the vector (at least in my config, osx10.5.7, xcode3.1.3, of006)

thanks for your vector access code too, is simpler to use a for loop over the vector

best regards

a

dynmem+vector2.zip

hi

your problem lies not in the destruction of your explosion-objects, the source of your problem is a missing copy-constructor for the explosion class.

  
  
void add(){  
      Explosion p;  
      myparts.push_back(p);  
   }  
  

What do these lines? In line 2 an explosion objects gets constructed. myparts.push_back push p onto its vector, for that it has to construct a new explosion object using the standard copy-constructor of explosion. In line 3 p get destructed, because it’s on the stack, remember, a copy of p is pushed onto the vector.

So what’s the problem with the standard copy-constructor? It just copies the values, it doesn’t know, what to do with verts, so it is only copying the address, without copying the objects. So when the p get destructed, the copy of p in the vector point to memory, which es freed already, so undefined behavior occurs.

I think, the best way would to use a vector for your vertices, the Standard Library takes care of copying the values etc.

Another possibility would be to create the Explosions on the heap via p= new Explosion();

HTH,
Stephan

thank you sth, it helped a lot. you brought me back my coding sanity and a nice tutorial on stack/heap, copy-constructors, vectors.

the code now runs flawlessly, with the deallocation of memory on the destructor, and no leaks!

i went for the 2nd solution you presented, handier for lots of code: transformed the myparts vector into a vector of pointers, the add function now puts objects on the heap, and proper deletion of objects and pointers on the managers update’s for loop. (i think…)

this is what it looks like now.

  
  
class ExplosionManager{  
public:  
	vector <Explosion *> myparts;  
	ExplosionManager(){;}  
	~ExplosionManager(){;}	  
	void update(){	  
		for(int i=0; i<myparts.size();i++){  
			myparts[i]->update();  
			if(myparts[i]->life==0){  
				delete myparts[i]; //delete the object allocated in add, calling its destructor  
				myparts.erase(myparts.begin()+i); // delete the pointer in vector  
				i--; // fix the index  
			}			  
		}		  
	}  
	void add(){  
		myparts.push_back(new Explosion());  
	}  
	void render(){  
		for(int i=0; i< myparts.size(); i++){			  
			myparts[i]->render();  
		}	 	  
	}  
};  
  

Hi as,

nice to hear that you found a working solution!

cheers,
Stephan

hi sth

you bet!:slight_smile:

cheers!

ps: i owe you and zach and damian a big p(o)int!:slight_smile:
if u’r around lx, pt, drop me a line, i’ll do the same next time in .de

a