By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,370 Members | 1,534 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,370 IT Pros & Developers. It's quick & easy.

Storing objects in a vector

P: n/a
I have the ff code for testing the concept of storing objects:

#include <vector>
#include <iostream>

using namespace std ;

class MyClass {
public:
MyClass(){
cout << "Default cstor called !" << endl ;
i = new int ;
*i = 100 ;
}

MyClass( const MyClass& m) {
cout << "Copy cstor called !" << endl ;
this->i = new int ;
*(this->i) = *(m.i);
}

MyClass& operator=( const MyClass& m) {
cout << "Assignment called !" << endl ;
if (this != &m) {
MyClass tmp(m) ;
std::swap(this->i, tmp.i ) ;
}
return *this ;
}

virtual ~MyClass(){
cout << "dstor called !" << endl ;
delete i ;
}

int getVal(void){ return *i ; }
void setVal(int v){ *i=v ;}

private:
int* i ;
};

int main(int argc, char* argv[])
{
MyClass mc ;
std::vector<MyClass> mv ;

mv.push_back(mc) ;
cout << "Element 0 of the vector has i value : " << mv[0].getVal() <<
endl ;
cout << "Setting i value to 123\n" ;
mv[0].setVal(123) ;
cout << "Element 0 of the vector now has i value : " << mv[0].getVal()
<< endl ;
mv.clear() ;
cout << "(After clear) size of vector is : " << mv.size() << endl ;

return 0;
}
Here is output from the console (code execution point is at the point
where variable mc has been "pushed back" into the vector).

Default cstor called !
Copy cstor called !
Copy cstor called !
dstor called !
I have the the following questions:

1). Why is the copy constructor called TWICE?
2). Why is the destructor called after mc has been pushed into the vector?
3). Does the vector implementation guarantee that it will free my
(contained) objects when:
(i) erase() is invoked
(ii) clear() is invoked
(iii) vector goes out of scope?

- since a vector stores a copy of the item to be stored, it behooves me
to delete the original variables (the copies of which are stored in the
vector), since I do not want two copies, "floating about" and consuming
resources - maybe it would be better to store pointers to my object
instead in the vector?. Storing copies rather than the original items in
a vector seems quite an inefficient/expensive way of going about things
- i.e. :

i). Object creation
ii). Making a copy of the object (vector stores a copy not original)
iii). Deleting the original object (so only the copy in the vector is
kept) - to mimimise resource consumption

It just dosen't seem right ... deleting an object that has just been
created (purely for the purposes of making a copy) seems just plain
silly ... Please say it isn't so ...

What (if anything) am I missing?

Looking forward to some insightful answers. Many thanks

Al
Jul 23 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a
Alfonso Morra wrote:
I have the ff code for testing the concept of storing objects:

#include <vector>
#include <iostream>

using namespace std ;

class MyClass {
public:
MyClass(){
cout << "Default cstor called !" << endl ;
i = new int ;
*i = 100 ;
}

MyClass( const MyClass& m) {
cout << "Copy cstor called !" << endl ;
this->i = new int ;
*(this->i) = *(m.i);
}

MyClass& operator=( const MyClass& m) {
cout << "Assignment called !" << endl ;
if (this != &m) {
MyClass tmp(m) ;
std::swap(this->i, tmp.i ) ;
}
return *this ;
}

virtual ~MyClass(){
cout << "dstor called !" << endl ;
delete i ;
}

int getVal(void){ return *i ; }
void setVal(int v){ *i=v ;}

private:
int* i ;
};

int main(int argc, char* argv[])
{
MyClass mc ;
std::vector<MyClass> mv ;

mv.push_back(mc) ;
cout << "Element 0 of the vector has i value : " << mv[0].getVal() <<
endl ;
cout << "Setting i value to 123\n" ;
mv[0].setVal(123) ;
cout << "Element 0 of the vector now has i value : " << mv[0].getVal()
<< endl ;
mv.clear() ;
cout << "(After clear) size of vector is : " << mv.size() << endl ;

return 0;
}
Here is output from the console (code execution point is at the point
where variable mc has been "pushed back" into the vector).

Default cstor called !
Copy cstor called !
Copy cstor called !
dstor called !
Check again, the output above is wrong:
You trace all calls to constructors, assignment operator
and destructor, i.e., the number of calls to the first two
must balance with the destructor calls.


I have the the following questions:

1). Why is the copy constructor called TWICE? Not if I compile and run your program.
2). Why is the destructor called after mc has been pushed into the vector? Because push_back creates a copy.
3). Does the vector implementation guarantee that it will free my
(contained) objects when:
(i) erase() is invoked
(ii) clear() is invoked
(iii) vector goes out of scope? The destructor of the "contained objects" will be called,
no memory is freed by the vector except for the last case.

- since a vector stores a copy of the item to be stored, it behooves me
to delete the original variables (the copies of which are stored in the
vector), since I do not want two copies, "floating about" and consuming
resources - maybe it would be better to store pointers to my object
instead in the vector?. Storing copies rather than the original items in
a vector seems quite an inefficient/expensive way of going about things
- i.e. :
Think again: How whould you store the original item in the vector?
Could you provide the pseudo code for it?

If the copy construction of a class is expensive, you may use
std::vector<Class*> as STL-container, however then you'll need
to provide a wrapper class that takes care of copy, asssignment
and destruction of the vector.

i). Object creation
ii). Making a copy of the object (vector stores a copy not original)
iii). Deleting the original object (so only the copy in the vector is
kept) - to mimimise resource consumption

It just dosen't seem right ... deleting an object that has just been
created (purely for the purposes of making a copy) seems just plain
silly ... Please say it isn't so ...

What (if anything) am I missing?

Looking forward to some insightful answers. Many thanks

Al


Jul 23 '05 #2

P: n/a


Stephan Brönnimann wrote:
Alfonso Morra wrote:
I have the ff code for testing the concept of storing objects:

#include <vector>
#include <iostream>

using namespace std ;

class MyClass {
public:
MyClass(){
cout << "Default cstor called !" << endl ;
i = new int ;
*i = 100 ;
}

MyClass( const MyClass& m) {
cout << "Copy cstor called !" << endl ;
this->i = new int ;
*(this->i) = *(m.i);
}

MyClass& operator=( const MyClass& m) {
cout << "Assignment called !" << endl ;
if (this != &m) {
MyClass tmp(m) ;
std::swap(this->i, tmp.i ) ;
}
return *this ;
}

virtual ~MyClass(){
cout << "dstor called !" << endl ;
delete i ;
}

int getVal(void){ return *i ; }
void setVal(int v){ *i=v ;}

private:
int* i ;
};

int main(int argc, char* argv[])
{
MyClass mc ;
std::vector<MyClass> mv ;

mv.push_back(mc) ;
cout << "Element 0 of the vector has i value : " << mv[0].getVal() <<
endl ;
cout << "Setting i value to 123\n" ;
mv[0].setVal(123) ;
cout << "Element 0 of the vector now has i value : " << mv[0].getVal()
<< endl ;
mv.clear() ;
cout << "(After clear) size of vector is : " << mv.size() << endl ;

return 0;
}
Here is output from the console (code execution point is at the point
where variable mc has been "pushed back" into the vector).

Default cstor called !
Copy cstor called !
Copy cstor called !
dstor called !

Check again, the output above is wrong:
You trace all calls to constructors, assignment operator
and destructor,


What does that mean in plain English ?

i.e., the number of calls to the first two must balance with the destructor calls.

Huh?

I have the the following questions:

1). Why is the copy constructor called TWICE?
Not if I compile and run your program.


Hmm ....

2). Why is the destructor called after mc has been pushed into the vector?
Because push_back creates a copy.


I dont understand the point you're making, creating a copy of a variable
is not the same as deleting the variable - in other words, the fact that
a copy is made of variable mc does not explain why it is fred.

3). Does the vector implementation guarantee that it will free my
(contained) objects when:
(i) erase() is invoked
(ii) clear() is invoked
(iii) vector goes out of scope?


The destructor of the "contained objects" will be called,
no memory is freed by the vector except for the last case.


Once again, your response seems inconsistent. If the destructor of
"contained objects" is invoked, then - memory is being freed (this is
certainly true in the example I gave of contained object MyClass)
- since a vector stores a copy of the item to be stored, it behooves me
to delete the original variables (the copies of which are stored in the
vector), since I do not want two copies, "floating about" and consuming
resources - maybe it would be better to store pointers to my object
instead in the vector?. Storing copies rather than the original items in
a vector seems quite an inefficient/expensive way of going about things
- i.e. :

Think again: How whould you store the original item in the vector?
Could you provide the pseudo code for it?

If the copy construction of a class is expensive, you may use
std::vector<Class*> as STL-container, however then you'll need
to provide a wrapper class that takes care of copy, asssignment
and destruction of the vector.

This is axiomatic. I wanted to know *what* (if any) resource management
std::vector provides "out of the box", so I can decide if I need to
"roll my own" resource management logic.
i). Object creation
ii). Making a copy of the object (vector stores a copy not original)
iii). Deleting the original object (so only the copy in the vector is
kept) - to mimimise resource consumption

It just dosen't seem right ... deleting an object that has just been
created (purely for the purposes of making a copy) seems just plain
silly ... Please say it isn't so ...

What (if anything) am I missing?

Looking forward to some insightful answers. Many thanks

Al



Jul 23 '05 #3

P: n/a
Alfonso Morra wrote:
I have the ff code for testing the concept of storing objects:

#include <vector>
#include <iostream>

using namespace std ;

class MyClass {
public:
MyClass(){
cout << "Default cstor called !" << endl ;
i = new int ;
*i = 100 ;
}

MyClass( const MyClass& m) {
cout << "Copy cstor called !" << endl ;
this->i = new int ;
*(this->i) = *(m.i);
}

MyClass& operator=( const MyClass& m) {
cout << "Assignment called !" << endl ;
if (this != &m) {
MyClass tmp(m) ;
std::swap(this->i, tmp.i ) ;
}
return *this ;
}

virtual ~MyClass(){
cout << "dstor called !" << endl ;
delete i ;
}

int getVal(void){ return *i ; }
void setVal(int v){ *i=v ;}

private:
int* i ;
};

int main(int argc, char* argv[])
{
MyClass mc ;
std::vector<MyClass> mv ;

mv.push_back(mc) ;
cout << "Element 0 of the vector has i value : " << mv[0].getVal()
<< endl ;
cout << "Setting i value to 123\n" ;
mv[0].setVal(123) ;
cout << "Element 0 of the vector now has i value : " <<
mv[0].getVal() << endl ;
mv.clear() ;
cout << "(After clear) size of vector is : " << mv.size() << endl ;

return 0;
}
Here is output from the console (code execution point is at the point
where variable mc has been "pushed back" into the vector).

Default cstor called !
Copy cstor called !
Copy cstor called !
dstor called !
I have the the following questions:

1). Why is the copy constructor called TWICE?
Not sure. My implentation seems to make a temporary local copy, before copying it to where it will end up.
2). Why is the destructor called after mc has been pushed into the vector?
The temporary copy goes out of scope.
3). Does the vector implementation guarantee that it will free my
(contained) objects when:
(i) erase() is invoked
Yes.
(ii) clear() is invoked
Should be equivelant to:
vec.erase(vec.begin(), vec.end())
(iii) vector goes out of scope?
Yes.

But remember that if you use pointers to your objects, it is the pointers it both copies AND deletes, not the objects they point to.
- since a vector stores a copy of the item to be stored, it behooves me
to delete the original variables (the copies of which are stored in the
vector), since I do not want two copies, "floating about" and consuming
resources - maybe it would be better to store pointers to my object
instead in the vector?. Storing copies rather than the original items in
a vector seems quite an inefficient/expensive way of going about things
- i.e. :

i). Object creation
ii). Making a copy of the object (vector stores a copy not original)
iii). Deleting the original object (so only the copy in the vector is
kept) - to mimimise resource consumption

It just dosen't seem right ... deleting an object that has just been
created (purely for the purposes of making a copy) seems just plain
silly ... Please say it isn't so ...

What (if anything) am I missing?


The fact that copying probably isn't as expensive as you think, and that you shouldn't prematurely optimise.

You could use a reference counted pointer to store your objects if they really are that expensive to copy. Look at boost smart pointers:
http://www.boost.org/libs/smart_ptr/smart_ptr.htm

Benchmark both approaches, but don't forget that something like a reference counted pointer introduces overhead too (counting when you copy, and indirection when you access)

Ben
--
I'm not just a number. To many, I'm known as a String...
Jul 23 '05 #4

P: n/a
Alfonso Morra wrote:


Stephan Brönnimann wrote:

Check again, the output above is wrong:
You trace all calls to constructors, assignment operator
and destructor,

What does that mean in plain English ?


It means he didn;t read the bit that said you hadn't completed the program.
i.e., the number of calls to the first two
must balance with the destructor calls.


Huh?


In total, you should have 1 construction, 2 copies and 3 destructions.
I have the the following questions:

1). Why is the copy constructor called TWICE?

Not if I compile and run your program.

Hmm ....


I get two copies when compiled and run.

Ben
--
I'm not just a number. To many, I'm known as a String...
Jul 23 '05 #5

P: n/a


Ben Pope wrote:
Alfonso Morra wrote:


Stephan Brönnimann wrote:

>> Check again, the output above is wrong:
You trace all calls to constructors, assignment operator
and destructor,


What does that mean in plain English ?

It means he didn;t read the bit that said you hadn't completed the program.
i.e., the number of calls to the first two
must balance with the destructor calls.


Huh?

In total, you should have 1 construction, 2 copies and 3 destructions.
I have the the following questions:

1). Why is the copy constructor called TWICE?

Not if I compile and run your program.


Hmm ....

I get two copies when compiled and run.

Ben


Thanks for the clarification Ben. Your previous post was veery useful
also - atleast I know I'm not going mad (w.r.t to the copy constructor
being called twice :-) )

Jul 23 '05 #6

P: n/a


Alfonso Morra wrote:
Stephan Brönnimann wrote:
2). Why is the destructor called after mc has been pushed into the vector?
Because push_back creates a copy.


I dont understand the point you're making, creating a copy of a variable
is not the same as deleting the variable - in other words, the fact that
a copy is made of variable mc does not explain why it is fred.


Please be precise about the meaning of "deleting the variable" and
"fred".
Does it mean "the destructor of MyClass is called."
or does it mean "an object of MyClass is deleted?

3). Does the vector implementation guarantee that it will free my
(contained) objects when:
(i) erase() is invoked
(ii) clear() is invoked
(iii) vector goes out of scope?


The destructor of the "contained objects" will be called,
no memory is freed by the vector except for the last case.


Once again, your response seems inconsistent. If the destructor of
"contained objects" is invoked, then - memory is being freed (this is
certainly true in the example I gave of contained object MyClass)


I your special case I agree, but that is because of ~MyClass()
and not because of the vector. Consider: what should happen
for std::vector<int>?

Think again: How whould you store the original item in the vector?
Could you provide the pseudo code for it?

If the copy construction of a class is expensive, you may use
std::vector<Class*> as STL-container, however then you'll need
to provide a wrapper class that takes care of copy, asssignment
and destruction of the vector.

This is axiomatic. I wanted to know *what* (if any) resource management
std::vector provides "out of the box", so I can decide if I need to
"roll my own" resource management logic.


std::vector manages its own allocated memory, that's it.
The memory management of the vector's content is up to you.

regards, Stephan

Jul 23 '05 #7

P: n/a


Stephan Brönnimann wrote:

Alfonso Morra wrote:
Stephan Brönnimann wrote:

2). Why is the destructor called after mc has been pushed into the vector?

Because push_back creates a copy.
I dont understand the point you're making, creating a copy of a variable
is not the same as deleting the variable - in other words, the fact that
a copy is made of variable mc does not explain why it is fred.

Please be precise about the meaning of "deleting the variable" and
"fred".
Does it mean "the destructor of MyClass is called."
or does it mean "an object of MyClass is deleted?

This is a typo. I meant to type "freed". By deleting the variable, I
meant any operation such as an erase, clear invokation on the vector,
that would cause an element to be deleted or erased (syntactic sugar)

3). Does the vector implementation guarantee that it will free my
(contained) objects when:
(i) erase() is invoked
(ii) clear() is invoked
(iii) vector goes out of scope?

The destructor of the "contained objects" will be called,
no memory is freed by the vector except for the last case.


Once again, your response seems inconsistent. If the destructor of
"contained objects" is invoked, then - memory is being freed (this is
certainly true in the example I gave of contained object MyClass)

I your special case I agree, but that is because of ~MyClass()
and not because of the vector. Consider: what should happen
for std::vector<int>?

Please see my comment below
Think again: How whould you store the original item in the vector?
Could you provide the pseudo code for it?

If the copy construction of a class is expensive, you may use
std::vector<Class*> as STL-container, however then you'll need
to provide a wrapper class that takes care of copy, asssignment
and destruction of the vector.


This is axiomatic. I wanted to know *what* (if any) resource management
std::vector provides "out of the box", so I can decide if I need to
"roll my own" resource management logic.

std::vector manages its own allocated memory, that's it.
The memory management of the vector's content is up to you.

regards, Stephan


Jul 23 '05 #8

P: n/a
Alfonso Morra wrote:


Stephan Brönnimann wrote:

Alfonso Morra wrote:
Stephan Brönnimann wrote:
> 2). Why is the destructor called after mc has been pushed into the
> vector?

Because push_back creates a copy.

I dont understand the point you're making, creating a copy of a variable
is not the same as deleting the variable - in other words, the fact that
a copy is made of variable mc does not explain why it is fred.


Please be precise about the meaning of "deleting the variable" and
"fred".
Does it mean "the destructor of MyClass is called."
or does it mean "an object of MyClass is deleted?

This is a typo. I meant to type "freed". By deleting the variable, I
meant any operation such as an erase, clear invokation on the vector,
that would cause an element to be deleted or erased (syntactic sugar)


I'm not sure what you think is syntactic suger. When you request for the copntainer to remove the element, the container will call the destructor of that item, and then remove
that item from the container and then deallocate any memory required to store that item. If that item is a pointer, and you allocated memory at the end of that pointer, thats
still your responsibility.

Ben
--
I'm not just a number. To many, I'm known as a String...
Jul 23 '05 #9

P: n/a


Ben Pope wrote:
Alfonso Morra wrote:


Stephan Brönnimann wrote:

Alfonso Morra wrote:

Stephan Brönnimann wrote:
>> 2). Why is the destructor called after mc has been pushed into the
>> vector?
>
>
> Because push_back creates a copy.
I dont understand the point you're making, creating a copy of a
variable
is not the same as deleting the variable - in other words, the fact
that
a copy is made of variable mc does not explain why it is fred.
Please be precise about the meaning of "deleting the variable" and
"fred".
Does it mean "the destructor of MyClass is called."
or does it mean "an object of MyClass is deleted?

This is a typo. I meant to type "freed". By deleting the variable, I
meant any operation such as an erase, clear invokation on the vector,
that would cause an element to be deleted or erased (syntactic sugar)

I'm not sure what you think is syntactic suger. When you request for
the copntainer to remove the element, the container will call the
destructor of that item, and then remove that item from the container
and then deallocate any memory required to store that item. If that
item is a pointer, and you allocated memory at the end of that pointer,
thats still your responsibility.

Ben


Thats not what I meant, (the term syntactic sugar being overloaded in
this particular usage) I was just being lazy and meant to say, the
phrases "deleting an object", "an objects destructor is called" are in
most cases, (certainly in this case) equivalent, and is largely a matter
of "syntax" (not in the computer language terminolgy sense).

Jul 23 '05 #10

P: n/a
In your case which deals with std::vector<MyClass>
calling ~MyClass() and to delete an allocated object of MyClass
is exactly not the same!

Just to prevent your next missunderstanding:
If you delete a pointer to an object the destructor of that object is
called.

Stephan

Jul 23 '05 #11

P: n/a


Stephan Brönnimann wrote:
In your case which deals with std::vector<MyClass>
calling ~MyClass() and to delete an allocated object of MyClass
is exactly not the same!

Just to prevent your next missunderstanding:
If you delete a pointer to an object the destructor of that object is
called.
This is exactly what I'm saying ...
Stephan


Jul 23 '05 #12

P: n/a
Alfonso Morra wrote:

int main(int argc, char* argv[])
{
MyClass mc ;
std::vector<MyClass> mv ;
mv.push_back(mc) ;
}

Here is output from the console (code execution point is at the point
where variable mc has been "pushed back" into the vector).

Default cstor called !
Copy cstor called !
Copy cstor called !
dstor called !

I have the the following questions:

1). Why is the copy constructor called TWICE?
2). Why is the destructor called after mc has been pushed into the vector?
One possibility is if your compiler's "push_back" function is
declared as taking an object by value (rather than by reference).
Then the extra creating and destruction is this local variable
in the push_back() function. You could confirm this by examining
your compiler's header files.

I can't think of any good reason why push_back would be declared
as taking the parameter by value though (mine takes it by reference),
and I don't know if this should be considered a compiler bug or not.
ISTR that compilers are allowed to make extra copies of objects
whenever they feel the need.
instead in the vector?. Storing copies rather than the original items
in a vector seems quite an inefficient/expensive way of going about
things i). Object creation
ii). Making a copy of the object (vector stores a copy not original)
iii). Deleting the original object (so only the copy in the vector is
kept) - to mimimise resource consumption
You don't need to delete the original object right away.
In your example you could use 'mc' for other things (eg. fill
out more data to it and push_back() it again).
It just dosen't seem right ... deleting an object that has just been
created (purely for the purposes of making a copy) seems just plain
silly ... Please say it isn't so ...


So why do you declare a temporary object and delete it a moment
later, in your assignment operator? :)

Jul 23 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.