473,387 Members | 1,789 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

problems of storing dynamically created objects in a vector

Hello,

I have a program that stores dynamically created objects into a
vector.

#include<iostream>
#include<vector>

using namespace std;

class A{
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
};

int main(){
vector<Av;
v.push_back(*new A);
v.push_back(*new A);
v.push_back(*new A);

return 0;
}

I output the messages for A() and ~A() to see what's been constructed/
destructed. Here is the output,

A()
A()
~A()
A()
~A()
~A()
~A()
~A()
~A()

This is quite surprising, as I expected the output to be

A()
A()
A()
~A()
~A()
~A()

because the program makes three new A objects and pushed them onto the
vector, hence I think there should be three consecutive A(), without
a "~A()" between the 2nd and 3rd "A()". When the vector is destroyed,
I think all its stored objects are destroyed, hence there should be
three "~A()". What's my mistake?

I also tried to store the pointers into the vector:

#include<iostream>
#include<vector>

using namespace std;

class A{
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
};

int main(){
vector<A*v;
v.push_back(new A);
v.push_back(new A);
v.push_back(new A);

return 0;
}

Now the output is only

A()
A()
A()

It seems the three objects are never destroyed. I guess when a vector
is destroyed, if its contents are pointers, then the pointers are
destroyed, but not the pointed objects. Is this correct?

Finally, can someone please tell me what's the correct way to store
dynamically created objects into a vector?

Thanks,
Jess

Jun 10 '07 #1
10 2685
Jess wrote:
Hello,

I have a program that stores dynamically created objects into a
vector.

#include<iostream>
#include<vector>

using namespace std;

class A{
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
};

int main(){
vector<Av;
v.push_back(*new A);
v.push_back(*new A);
v.push_back(*new A);

return 0;
}

I output the messages for A() and ~A() to see what's been constructed/
destructed. Here is the output,

A()
A()
~A()
A()
~A()
~A()
~A()
~A()
~A()

This is quite surprising, as I expected the output to be
You are passing objects by value to push_back, when you do this the
compiler is using the compiler generated copy constructor to create a
temporary object and then destroying it. That's why you see more
destructor the constructor calls. Try adding your own copy constructor
and see this for your self:

A(const A&){cout << "A(const A&)" << endl;}
A()
A()
A()
~A()
~A()
~A()
Which it could be if the compiler were to optimise away the copies.
Now the output is only

A()
A()
A()

It seems the three objects are never destroyed. I guess when a vector
is destroyed, if its contents are pointers, then the pointers are
destroyed, but not the pointed objects. Is this correct?
It is.
Finally, can someone please tell me what's the correct way to store
dynamically created objects into a vector?
It depends on the size of the object, for small objects you may as well
sore by value, for larger ones, store a pointer and clean up when you
erase elements from the vector. For this, I would suggest you use some
form of smart pointer to do the hose keeping for you.

--
Ian Collins.
Jun 10 '07 #2
On 2007-06-10, Jess <wd***@hotmail.comwrote:
#include<iostream>
#include<vector>

using namespace std;

class A{
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
};
Before going any further, add a logging copy constructor (and a
logging assignment operator for completeness). You are missing a lot
of detail because you are logging all destructions, but not all
constructions. Something like:

A(const A&)
{ cout << "A(const A&)" << endl; }
A& operator=(const A&)
{ cout << "op=(const A&)" << endl; return *this; }
int main(){
vector<Av;
v.push_back(*new A);
v.push_back(*new A);
v.push_back(*new A);

return 0;
}
Here you are creating three new A objects and pushing a *copy* of each
into the vector. You are then never destroying the original objects.
int main(){
vector<A*v;
v.push_back(new A);
v.push_back(new A);
v.push_back(new A);

return 0;
}

It seems the three objects are never destroyed. I guess when a vector
is destroyed, if its contents are pointers, then the pointers are
destroyed, but not the pointed objects. Is this correct?
This is correct by the compiler. If you follow this pattern and you
have no other copy of the pointers through which to delete the objects
then you must be sure to manually delete each pointer in the vector
before either removing that pointer from the vector or letting the
vector by destroyed (e.g. by going out of scope).
Jun 10 '07 #3

Jess <wd***@hotmail.comwrote in message...
Hello,
I have a program that stores dynamically created objects into a
vector.
[snip]
Read the other posts first, if you haven't.

Putting it all together (assuming you don't want to use a 'smart pointer',
as Ian mentioned), here's a little demo:

// #includes here
#include<iostream>
#include<vector>
#include <sstream>
std::ostringstream out;

class A7{ public:
A7(){ out<<"A7()"<<std::endl;}
~A7(){ out<<"~A7()"<<std::endl;}
A7( A7 const &){ out<<"A7(const A7&)"<<std::endl;}
// A7& operator=( A7 const &){
// out<<"operator=( A7 const &)"<<std::endl;
// return *this;
// }
};

int main(){ using std::cout; // for NG post
cout<<"\n - A7 test -"<<std::endl;
{
std::vector<A7svA7( 3 );
out<<"- destructing -"<<std::endl;
}
out<<"-----"<<std::endl;
{
std::vector<A7*svA7( 3 );
// -- fill it --
for( std::vector<A7*>::iterator i( svA7.begin() );
i != svA7.end(); ++i ){
*i = new A7;
}
out<<"-----"<<std::endl;
// -- clean it out --
for( std::vector<A7*>::iterator i( svA7.begin() );
i != svA7.end(); ++i ){
delete *i;
// *i = 0; // in case it gets called again (if function)
}
}
cout<<out.str()<<std::endl;
out.clear(); out.str("");
cout<<"\n - A7 test - END"<<std::endl;
return 0;
}// main()

[ Why 'out'? Because that's the way I needed to try it in my TestBench pgm,
and I just didn't feel like changing them all back to std::cout. <G]
--
Bob R
POVrookie
Jun 10 '07 #4

Ian Collins wrote in message...
ref:
Finally, can someone please tell me what's the correct way to store
dynamically created objects into a vector?
It depends on the size of the object, for small objects you may as well
sore by value, for larger ones, store a pointer and clean up when you
erase elements from the vector. For this, I would suggest you use some
form of smart pointer to do the hose keeping for you.
Hi Ian,

Sometimes 'typos' are bad, sometimes they are good.
By the time I got through 'sore by value' and 'hose keeping', I was in
belly-laughs. Thanks, I needed that. ;-}

--
Bob R
POVrookie
Jun 10 '07 #5
BobR wrote:
Ian Collins wrote in message...
>ref:
>>Finally, can someone please tell me what's the correct way to store
dynamically created objects into a vector?
It depends on the size of the object, for small objects you may as well
sore by value, for larger ones, store a pointer and clean up when you
erase elements from the vector. For this, I would suggest you use some
form of smart pointer to do the hose keeping for you.

Hi Ian,

Sometimes 'typos' are bad, sometimes they are good.
By the time I got through 'sore by value' and 'hose keeping', I was in
belly-laughs. Thanks, I needed that. ;-}
That'll teach me to type and talk on the phone at the same time!

--
Ian Collins.
Jun 10 '07 #6
On Jun 10, 3:43 pm, "BobR" <removeBadB...@worldnet.att.netwrote:
Jess <w...@hotmail.comwrote in message...
Hello,
I have a program that stores dynamically created objects into a
vector.
[snip]

Read the other posts first, if you haven't.

Putting it all together (assuming you don't want to use a 'smart pointer',
as Ian mentioned), here's a little demo:

// #includes here
#include<iostream>
#include<vector>
#include <sstream>
std::ostringstream out;

class A7{ public:
A7(){ out<<"A7()"<<std::endl;}
~A7(){ out<<"~A7()"<<std::endl;}
A7( A7 const &){ out<<"A7(const A7&)"<<std::endl;}
// A7& operator=( A7 const &){
// out<<"operator=( A7 const &)"<<std::endl;
// return *this;
// }
};

int main(){ using std::cout; // for NG post
cout<<"\n - A7 test -"<<std::endl;
{
std::vector<A7svA7( 3 );
out<<"- destructing -"<<std::endl;
}
out<<"-----"<<std::endl;
{
std::vector<A7*svA7( 3 );
// -- fill it --
for( std::vector<A7*>::iterator i( svA7.begin() );
i != svA7.end(); ++i ){
*i = new A7;
}
out<<"-----"<<std::endl;
// -- clean it out --
for( std::vector<A7*>::iterator i( svA7.begin() );
i != svA7.end(); ++i ){
delete *i;
// *i = 0; // in case it gets called again (if function)
}
}
cout<<out.str()<<std::endl;
out.clear(); out.str("");
cout<<"\n - A7 test - END"<<std::endl;
return 0;
}// main()

[ Why 'out'? Because that's the way I needed to try it in my TestBench pgm,
and I just didn't feel like changing them all back to std::cout. <G]
--
Bob R
POVrookie

Thanks! I've run the example on my computer and here's what I've got:

- A7 test -
A7()
A7(const A7&)
A7(const A7&)
A7(const A7&)
~A7()
- destructing -
~A7()
~A7()
~A7()
-----
A7()
A7()
A7()
-----
~A7()
~A7()
~A7()

Where does the first A() come from? I guess when the vector of three
A7 objects is constructed perhaps one A7 object is created first and
then copy constructor is called three times to copy the initial object
to the vector. Then the first ~A() means the initial A7 object is
destroyed? When is it destroyed? Furthermore, does a vector always
create an initial object and then destroy with the vector finishes
with it? I think this is what Ian meant? Is there any way that the
compiler doesn't create a temporary object?

Thanks,
Jess

Jun 10 '07 #7
On 2007-06-10, Jess <wd***@hotmail.comwrote:
>
- A7 test -
A7()
A7(const A7&)
A7(const A7&)
A7(const A7&)
~A7()
- destructing -
~A7()
~A7()
~A7()
-----
A7()
A7()
A7()
-----
~A7()
~A7()
~A7()

Where does the first A() come from? I guess when the vector of three
A7 objects is constructed perhaps one A7 object is created first and
then copy constructor is called three times to copy the initial object
to the vector. Then the first ~A() means the initial A7 object is
destroyed? When is it destroyed? Furthermore, does a vector always
create an initial object and then destroy with the vector finishes
with it? I think this is what Ian meant? Is there any way that the
compiler doesn't create a temporary object?

Thanks,
Jess
When the initial vector of size three is created the vector
implementation needs to create three instances of A which are
equivalent to default constructed As. Some classes can be optimized
to share common data so sometimes it's more efficient to create a set
of objects by copying a template object several times rather that
constructing them identically but independently. This is what this
vector implementation has chosen to do. It creates a blank template
object, copies it three times into the new vector and throws the
template away. As far as I'm aware it would have been perfectly valid
for the vector to have default constructed the three objects in which
case your logging would have shown as below, which might have been
what you expected initially.
- A7 test -
A7()
A7()
A7()
- destructing -
~A7()
~A7()
~A7()
-----
Part of the contract that your objects must comply to if you want to
place them in a vector is that copying them must "work". You
shouldn't rely on whether or how the implementation uses temporaries
or how often and when it will copy instances of your class, but
equally you should be aware of how vector will interact with your
class when you design it.
Jun 10 '07 #8

Jess wrote in message...
On Jun 10, 3:43 pm, "BobR" wrote:
>[snip]
class A7{ public:
// A7(){ out<<"A7()"<<std::endl;}
A7() : MyVal(5){ out<<"A7()"<<std::endl;}
~A7(){ out<<"~A7()"<<std::endl;}
A7( A7 const &){ out<<"A7(const A7&)"<<std::endl;}
// A7& operator=( A7 const &aa){
// out<<"operator=( A7 const &)"<<std::endl;
MyVal = aa.MyVal;
// Thing = new MyThing; // not Thing = aa.Thing!!!
// in copy-Ctor too? Try it. don't forget to delete Thing.
// return *this;
// }
int MyVal;
// MyThing *Thing; // = new MyThing;
};

Thanks! I've run the example on my computer and here's what I've got:
[snip same output I got on GCC(MinGW)]
>
Where does the first A() come from? I guess when the vector of three
A7 objects is constructed perhaps one A7 object is created first and
then copy constructor is called three times to copy the initial object
to the vector. Then the first ~A() means the initial A7 object is
destroyed? When is it destroyed?
( see Mr. Bailey's post )
I put the 'destructing' line in so you could see that the temporary (if one)
does not get destructed by going out of scope. The vectors constructor
handles it.

Now experiment; add a couple 'push_back' ops to see what happens:
{
std::vector<A7svA7( 3 );
out<<"- push_back -"<<std::endl;
{ // an extra scope ....
A7 tmp;
svA7.push_back( tmp );
svA7.push_back( tmp );
out<<"- push_back done -"<<std::endl;
} // ....to cause 'tmp' to destruct
// you mignt think that because 'tmp' no longer exists, the
// 'svA7' objects were now invalid. Are they (hint: cout)?
// ( put an 'int MyVal;' in your class, and output that.)
out<<"- destructing -"<<std::endl;
}
Furthermore, does a vector always
create an initial object and then destroy with the vector finishes
with it?
The temporary 'A7' you see? It's not guaranteed (AFAIK), left to the
implementation.
When the vector goes out-of-scope, or is otherwise destructed, it calls the
destructors for all the objects it holds. If the vector holds pointers, it
destructs the pointers, but not what they point to ( that's your
responsibility, or the 'smart-pointers' if you use them (that's their strong
point).).

You'll notice in your class that I showed (but commented-out) the
'operator=()'. That *may* become important if you put something in your
class, like a pointer to an dynamically created ('new') object. If you
simply copy the pointer content to a next A7 object, you now have two
pointers to the same memory area. One A7 gets destroyed, which deletes the
dyn. object, and then leaves the copy holding a pointer to something that no
longer exists - UB! So, add something to your class, uncomment the
assignment operator, and do some experiments (vecA = vecB;, etc..). Do not
be afraid to experiment, learn from mistakes. Thimk! <G>

I think this is what Ian meant? Is there any way that the
compiler doesn't create a temporary object?
Did you see temps in the output of the second section (where 'new' was
used)?
(ok, bad example ('cause it's pointers). Implementation thing again.)

[ corrections always welcome ]
--
Bob R
POVrookie
Jun 10 '07 #9

BobR wrote in message...
>
So, add something to your class, uncomment the
assignment operator, and do some experiments
** (vecA = vecB;, etc..). **
......more like:
std::vector<A7svA7_2;
svA7_2 = svA7; // just copies vector
svA7_2.at(0) = svA7.at(1); // for operator=()
.... or just
svA7.at(0) = svA7.at(1); // for operator=()
[ corrections always welcome ]
--
Bob R
POVrookie
Jun 10 '07 #10
On Jun 10, 1:56 pm, Jess <w...@hotmail.comwrote:
On Jun 10, 3:43 pm, "BobR" <removeBadB...@worldnet.att.netwrote:
Jess <w...@hotmail.comwrote in message...
[Code severely cut...]
class A7{ public:
A7(){ out<<"A7()"<<std::endl;}
~A7(){ out<<"~A7()"<<std::endl;}
A7( A7 const &){ out<<"A7(const A7&)"<<std::endl;}
// A7& operator=( A7 const &){
// out<<"operator=( A7 const &)"<<std::endl;
// return *this;
// }
};
int main(){ using std::cout; // for NG post
cout<<"\n - A7 test -"<<std::endl;
{
std::vector<A7svA7( 3 );
out<<"- destructing -"<<std::endl;
}
return 0;
}// main()
Thanks! I've run the example on my computer and here's what I've got:
- A7 test -
A7()
A7(const A7&)
A7(const A7&)
A7(const A7&)
~A7()
- destructing -
Where does the first A() come from?
What's the second argument to the constructor of the vector in
svA7?

The STL has been designed to work with classes without default
constructors, so it never uses a default constructor internally,
only the copy constructor or assignment.
I guess when the vector of three A7 objects is constructed
perhaps one A7 object is created first and then copy
constructor is called three times to copy the initial object
to the vector.
It's required, because the constructor is actually:

vector<T>::vector( size_type n, T const& = T() ) ;

Try replacing the default constructor with one which requires an
argument (say an int). You can still write:

vector< A7 svA7( 3, A7( 0 ) ) ;

for example.
Then the first ~A() means the initial A7 object is
destroyed?
The first ~A() is the destructor of the temporary object which
was passed as the second argument to the constructor of vector.
When is it destroyed?
As soon as we return from the constructor of vector.
Furthermore, does a vector always create an initial object and
then destroy with the vector finishes with it?
The vector doesn't. You must always supply it with an object
(or objects) to be copied, if the vector is not empty.
I think this is what Ian meant? Is there any way that the
compiler doesn't create a temporary object?
The standard requires it. I don't think that there's anyway you
(or the compiler) can avoid it.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 10 '07 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: Peter Olcott | last post by:
I want to be able to efficiently build data structures at run-time. These data structures need to be accessed with minimal time. The only a few ways that come immediately to mind would be some...
6
by: Jeff Williams | last post by:
Ok, everyone loves to talk about dynamic arrays and ptr's etc, they provide endless conversation :) so here goes: Will this leak memory (my intuition says yes): void foo(vector<int*>& vec) {...
6
by: Alfonso Morra | last post by:
I have written the following code, to test the concept of storing objects in a vector. I encounter two run time errors: 1). myClass gets destructed when pushed onto the vector 2). Prog throws a...
12
by: Alfonso Morra | last post by:
I have the ff code for testing the concept of storing objects: #include <vector> #include <iostream> using namespace std ; class MyClass { public: MyClass(){
0
by: mseeger | last post by:
My concrete problem is this (it is a bit special, but there may be other instances of it): I'd like to create a class for vectors (say: Vector), exporting math. methods, say v.foo(...). I'd like...
13
by: r.z. | last post by:
I logged construtor and destructor calls for one of my classes and I discovered that the constructor was called only once while the destructor was called 3 times for a single object. I have a...
4
by: H | last post by:
I'm trying to wrap my head around inheritance. The following code creates three objects, an Animal, a Dog and a Cat. Dog and Cat are derived from Animal and overwrite Animal's birth() method. I...
3
by: Ramon F Herrera | last post by:
Newbie alert: I come from C programming, so I still have that frame of mind, but I am trying to "Think in C++". In C this problem would be solved using unions. Hello: Please consider the...
3
by: Bruno.DiStefano | last post by:
Hi All, BACKGROUND INFO I need to use a "vector" structure to store a number of objects that becomes known only at run time. The constructor, at instantiation time of a new object, increments a...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.