• Advertisement
Sign in to follow this  

vectors (erase)

This topic is 3766 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

Ive been messing around with vectors trying to get my head around them, and am trying to figure out when the objects get deleted and why. using the code below, i get the following ouput http://i13.photobucket.com/albums/a280/benjidrummer/Untitled-6.jpg now, i understood it that the vector took references, when you use the pushback method, so why the first delete line, after pushing back jake?, and then, when creating bob, i get another 2 deletes, could anybody explain these deletes to me please, i know it has somthing to do with the copy constructor, but i dont understnad why this is used, if they are being passed as reference
#include <iostream>
#include <vector>

using namespace std;

class cats
{
public:
	cats(void)	{cout << "making a cat " << this << endl;}

	cats(const cats& p) {cout << "inside copy constructor " << endl;}

	~cats(void)	{cout << "--- deleting a cat " << this << endl;}


	int legs;
	int eyes;

};


int main()
{
	vector <cats> catFamily;

	
		cats *jake = new cats();
		cats *bob = new cats();

	cout << "pushback jake" << endl;
		catFamily.push_back(*jake);

	cout << "pushback bob" << endl;
		catFamily.push_back(*bob);
	

	cout << "cats made " << endl;

	for( vector <cats>::iterator it = catFamily.begin(); it != catFamily.end();)
	{
		it = catFamily.erase(it);
		
	}
	
	cout << "finish" << endl;
}


Share this post


Link to post
Share on other sites
Advertisement
Running the exact same code as you, I got this output:

making a cat 0x3f3ca8 // new cat
making a cat 0x3f3d28 // new cat
pushback jake
inside copy constructor // copied into vector
pushback bob
inside copy constructor // copied into vector
inside copy constructor // reallocate vector: copied from first vector
--- deleting a cat 0x3f3d38 // deleted contents from first vector
cats made
--- deleting a cat 0x3f3d50 // deleting vector contents: first cat
--- deleting a cat 0x3f3d48 // deleting vector contents: second cat
finish

Which seems perfectly fine, since you never delete those 2 pointers.

Share this post


Link to post
Share on other sites
The vector copies whatever you pass in, and works with copies throughout. Your original jake and bob elements don't go into the vector - copies of them do. And when you add things to the vector, sometimes it has to grow, which involves allocating more memory somewhere. The existing elements are copied across to the new memory, then the old memory is freed, leading to the destruction of the elements that were there before.

Also, don't 'new' objects that you're just using temporarily - this isn't Java. jake and bob should just be created on the stack, "cats jake;" and "cats bob;". (The class should probably also be called 'cat' rather than cats, since it's singular, but that's nit-picking.) Not only is it more efficient, but it's usually safer - you actually end up leaking the jake and bob objects here, because you do not call 'delete' on them before the pointers go out of scope. But then, you probably thought you needed to new these items for them to be stored in the vector, which isn't the case.

Share this post


Link to post
Share on other sites
argh right, that makes a little more sence, so vector doesn't modify the original,

so your in charge of freeing the vector array, and deleting the original? like the following.



#include <iostream>
#include <vector>

using namespace std;

class cats
{
public:
cats(void) {cout << "making a cat " << this << endl;}

cats(const cats& p) {cout << "inside copy constructor " << endl;}

~cats(void) {cout << "--- deleting a cat " << this << endl;}


int legs;
int eyes;

};


int main()
{
vector <cats> catFamily;


cats *jake = new cats();
cats *bob = new cats();

cout << "pushback jake" << endl;
catFamily.push_back(*jake);

cout << "pushback bob" << endl;
catFamily.push_back(*bob);


cout << "cats made " << endl;

for( vector <cats>::iterator it = catFamily.begin(); it != catFamily.end();)
{
it = catFamily.erase(it);

}

cout << "finish" << endl;

delete jake;
delete bob;
}

Share this post


Link to post
Share on other sites
You're right that your vector will not modify the original objects, but there is no need to keep the originals around after you call push_back for both of them, since from then on the vector only deals with its own copies.

You can call delete on the jake and bob pointers immediately after adding them to the vector. In fact, there's no need to allocate them on the heap at all.


int main()
{
vector <cats> catFamily;
cats jake, bob

cout << "pushback jake" << endl;
catFamily.push_back(jake);

cout << "pushback bob" << endl;
catFamily.push_back(bob);

cout << "cats made " << endl;

for( vector <cats>::iterator it = catFamily.begin(); it != catFamily.end();)
{
it = catFamily.erase(it);

}

cout << "finish" << endl;

return 0;
}



Share this post


Link to post
Share on other sites
You clean up the memory you allocate. The vector cleans up memory it allocates.

The vector also cleans up *objects that it copies into* the memory it allocates. "You" clean up the objects that you put in memory you allocate, too, but actually the language does it (it calls your object's destructor, or an automatically generated one if you don't write one).

So no, you don't need to .erase() each member of the vector: when the vector goes out of scope, *its* destructor is called, and its destructor will automatically call destructors of the objects that it's holding, and then deallocate the memory.

When you allocate Cat objects like that, you do need to 'delete' the pointers, which calls destructors on the pointed-at Cat objects, and then deallocates their memory. But the proper way to do things, in almost every case, is *not* to allocate Cat objects like that.

In code, it looks like:


int main() {
vector<Cat> catFamily;


Cat jake;
Cat bob;

cout << "pushback jake" << endl;
catFamily.push_back(jake);

cout << "pushback bob" << endl;
catFamily.push_back(bob);

// The vector contains a copy of jake, and a copy of bob.

cout << "cats made " << endl;

// You *could* empty the copies out of the vector yourself here, but
// there is no point, unless e.g. you want to then put a *different* set
// of Cats in.
} // The destructors of bob, jake and the vector are called, in that order -
// i.e., the reverse of the order that constructors were called.
// When the vector's destructor is called, it will in turn call the destructor
// of the copy of bob and then the copy of jake, and then deallocate the memory.
// You didn't allocate any memory directly, so there is no need to deallocate
// manually.

Share this post


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

  • Advertisement