Page 1 of 1

deleting an object

Posted: Sun May 16, 2010 4:23 pm
by short
Gonna cut out unnecessary code:

Code: Select all

class Particle_Emitter : Object
{
private:
	...
	// member variables
	Particle * s_Particle; // a single particle
        ...
public:

/* ||||||| DESTRUCTOR ||||||||| */
	~Particle_Emitter();
Inside the constructor of Particle_Emitter allocate_memory_particle is called on s_Particle:

Code: Select all

Particle_Emitter::Particle_Emitter(const unsigned int type, const unsigned int density)
{
	.....

	allocate_memory_particle(s_Type);

	init_particles();
}

Code: Select all

void Particle_Emitter::allocate_memory_particle(const unsigned int type)
{
	if(type == CIRCLE)
	{
		Particle * qp = new Particle(0.0f, 2*(float)M_PI);
		s_Particle = qp;
	}
}

Intuitively, I wrote the following destructor for particle_emitter:

Code: Select all

Particle_Emitter::~Particle_Emitter()
{
	delete(s_Particle);
}
Which throws an exception. I understand the idea in general, I've read through Bjarne's book a few times trying to get it and for some reason I'm missing what is going wrong here.
Well, I am allocating a new Particle() and setting s_Particle to point to it. So I thought it made sense that I need to pass that pointer to be freed.

Do any of you guys see where I'm going wrong? (The program has no problems running without the delete line in the destructor, I just didn't want to have a big fat memory leak). Thanks

Re: deleting an object

Posted: Sun May 16, 2010 5:08 pm
by short
I think editing my original post would make my progression unclear, so I'm posting a reply:

In particle_emitter I wrote the following function like this:

Code: Select all

void Particle_Emitter::deallocate_memory_particle()
{
	delete(s_Particle);
}
In my particle_system update method I have the following:

Code: Select all

void Particle_System::update()
{
	std::vector<Particle_Emitter>::iterator it; // Iterator

	for(it=o_Particle_Container.begin();it < o_Particle_Container.end();)
	{
		if(it->s_flag_onscreen == false && it->get_Repeat() == false)
		{
			// erase returns a pointer to the next object in the STL container
			it->deallocate_memory_particle();
			it = o_Particle_Container.erase(it);
		}
		// we only want to add to it if we don't delete an object, or we will add twice when we delete an object.
		else
		{
			it++;
		}
	}
}
This, seems to do the job. I don't think my misunderstanding is how delete/new works, but when the destructor is called. I know an objects destructor is called when said object goes "out of scope." Since I was using an stl container, the o_Particle_Container was calling the iterators destructor every finite interval, OK.

My question is, is this the best way you guys can see for deleting the allocated memory? Specifically calling a de-allocating method? If so, what's the point of having a destructor in the first place? (in this specific example)

Re: deleting an object

Posted: Mon May 17, 2010 11:05 am
by dandymcgee
This:

Code: Select all

Particle_Emitter::~Particle_Emitter()
{
   delete(s_Particle);
}
Should be:

Code: Select all

Particle_Emitter::~Particle_Emitter()
{
   delete s_Particle;
}
And if you do it this way:

Code: Select all

void Particle_Emitter::deallocate_memory_particle()
{
   delete(s_Particle);
}
You should also change delete:

Code: Select all

void Particle_Emitter::deallocate_memory_particle()
{
   delete s_Particle;
}
Some other (unimportant) points:

This:

Code: Select all

void Particle_Emitter::allocate_memory_particle(const unsigned int type)
{
   if(type == CIRCLE)
   {
      Particle * qp = new Particle(0.0f, 2*(float)M_PI);
      s_Particle = qp;
   }
}
Should probably be:

Code: Select all

void Particle_Emitter::allocate_memory_particle(const unsigned int type)
{
   if(type == CIRCLE)
   {
      s_Particle = new Particle(0.0f, 2*(float)M_PI);
   }
}

Re: deleting an object

Posted: Mon May 17, 2010 5:00 pm
by short
dandymcgee wrote:This:

Code: Select all

Particle_Emitter::~Particle_Emitter()
{
   delete(s_Particle);
}
Should be:

Code: Select all

Particle_Emitter::~Particle_Emitter()
{
   delete s_Particle;
}
What is the difference between the lack of parenthesis?

Re: deleting an object

Posted: Mon May 17, 2010 6:04 pm
by Bakkon
short wrote:What is the difference between the lack of parenthesis?
Just convention, I think. Parenthesis make it look like a function when its an operator. I've never actually seen it used like that before.

Re: deleting an object

Posted: Mon May 17, 2010 6:18 pm
by short
Bakkon wrote:
short wrote:What is the difference between the lack of parenthesis?
Just convention, I think. Parenthesis make it look like a function when its an operator. I've never actually seen it used like that before.
So removing the parenthesis wouldn't solve the issue, just a convention? And I concur, after looking at the code I agree the parenthesis do make it look like a fn, thanks.

Re: deleting an object

Posted: Mon May 17, 2010 6:34 pm
by qpHalcy0n
Have you supplied good copy constructors?

You may be pushing a copy somewhere, then when its destroyed you end up with two delete's.

Re: deleting an object

Posted: Mon May 17, 2010 7:16 pm
by Genesis
When a particle is deleted during the update() you need to specify that s_Particle no longer contains a valid pointer to object. You can do this using automated memory management with smart pointers (the example below uses std::shared_ptr from C++0x) or by setting the variable to 0 or NULL (or nullptr in C++0x). Setting the pointer to 0 after deleting will prevent invalid deletions of unallocated memory at a later point since delete(0) safely resolves to a no-op.

std::shared_ptr Version

Code: Select all

#include <memory>
class Particle_Emitter : Object
{
private:
	...
	// member variables
	std::shared_ptr<Particle> s_Particle; // a single particle
        ...
public:

/* ||||||| DESTRUCTOR ||||||||| */
	~Particle_Emitter();

Code: Select all

Particle_Emitter::Particle_Emitter(const unsigned int type, const unsigned int density)
{
	.....

	allocate_memory_particle(s_Type);

	init_particles();
}

Code: Select all

void Particle_Emitter::allocate_memory_particle(const unsigned int type)
{
	if(type == CIRCLE)
	{
		std::shared_ptr<Particle> qp(new Particle(0.0f, 2*(float)M_PI));
		s_Particle = qp;
	}
}

Code: Select all

Particle_Emitter::~Particle_Emitter()
{
	// Do Nothing Here Since shared_ptr Deallocates When Reference Count Is Zero
}

Code: Select all

void Particle_Emitter::deallocate_memory_particle()
{
	// Do Nothing Here Since shared_ptr Deallocates When Reference Count Is Zero
}

Code: Select all

void Particle_System::update()
{
	std::vector<Particle_Emitter>::iterator it; // Iterator

	for(it=o_Particle_Container.begin();it < o_Particle_Container.end();)
	{
		if(it->s_flag_onscreen == false && it->get_Repeat() == false)
		{
			// erase returns a pointer to the next object in the STL container
			it->deallocate_memory_particle();
			it = o_Particle_Container.erase(it);
		}
		// we only want to add to it if we don't delete an object, or we will add twice when we delete an object.
		else
		{
			it++;
		}
	}
}
--------------------------------------------------------------------------------------------

Regular Pointer Version

Code: Select all

class Particle_Emitter : Object
{
private:
	...
	// member variables
	Particle *s_Particle; // a single particle
        ...
public:

/* ||||||| DESTRUCTOR ||||||||| */
	~Particle_Emitter();

Code: Select all

Particle_Emitter::Particle_Emitter(const unsigned int type, const unsigned int density)
: s_Particle(0)
{
	.....

	allocate_memory_particle(s_Type);

	init_particles();
}

Code: Select all

void Particle_Emitter::allocate_memory_particle(const unsigned int type)
{
	if(type == CIRCLE)
	{
		Particle *qp = new Particle(0.0f, 2*(float)M_PI);
		s_Particle = qp;
	}
}

Code: Select all

Particle_Emitter::~Particle_Emitter()
{
	if(s_Particle) delete s_Particle;
}

Code: Select all

void Particle_Emitter::deallocate_memory_particle()
{
	if(s_Particle) delete s_Particle;
	s_Particle = 0;
}

Code: Select all

void Particle_System::update()
{
	std::vector<Particle_Emitter>::iterator it; // Iterator

	for(it=o_Particle_Container.begin();it < o_Particle_Container.end();)
	{
		if(it->s_flag_onscreen == false && it->get_Repeat() == false)
		{
			// erase returns a pointer to the next object in the STL container
			it->deallocate_memory_particle();
			it = o_Particle_Container.erase(it);
		}
		// we only want to add to it if we don't delete an object, or we will add twice when we delete an object.
		else
		{
			it++;
		}
	}
}

Re: deleting an object

Posted: Mon May 17, 2010 7:38 pm
by short
When a particle is deleted during the update() you need to specify that s_Particle no longer contains a valid pointer to object. You can do this using automated memory management with smart pointers (the example below uses std::shared_ptr from C++0x) or by setting the variable to 0 or NULL (or nullptr in C++0x). Setting the pointer to 0 after deleting will prevent invalid deletions of unallocated memory at a later point since delete(0) safely resolves to a no-op.
oh, wow! Thanks !! :] that really cleared things up for me. Yay for learning something new!! :] :]

Re: deleting an object

Posted: Mon May 17, 2010 10:57 pm
by dandymcgee
short wrote:
Bakkon wrote:
short wrote:What is the difference between the lack of parenthesis?
Just convention, I think. Parenthesis make it look like a function when its an operator. I've never actually seen it used like that before.
So removing the parenthesis wouldn't solve the issue, just a convention? And I concur, after looking at the code I agree the parenthesis do make it look like a fn, thanks.
I had never seen it like that before either (didn't even realize you could put parenthesis there), so I wasn't sure if it was causing a problem or not. Apparently it doesn't make a difference though. :roll: