Storing objects in a vector

A

Alfonso Morra

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
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

Alfonso said:
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.
 
A

Alfonso Morra

Stephan said:
Alfonso said:
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?


Not if I compile and run your program.

Hmm ....
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.
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)
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.
 
B

Ben Pope

Alfonso said:
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
 
A

Alfonso Morra

Ben said:
It means he didn;t read the bit that said you hadn't completed the program.



In total, you should have 1 construction, 2 copies and 3 destructions.



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 :) )
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

Alfonso said:
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?
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 said:
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
 
A

Alfonso Morra

Stephan said:
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 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
 
B

Ben Pope

Alfonso said:
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
 
A

Alfonso Morra

Ben said:
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).
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

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
 
A

Alfonso Morra

Stephan said:
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 ...
 
O

Old Wolf

Alfonso said:
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? :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top