What is the proper way of pushing a new object element onto a std::vector
? I want the data to be allocated in the vector. Will this copy the object newrad
By default, std::vector manages the memory itself using the copy constructor of the underlying class. So, it acts a bit as if the vector element was a local variable (when the vector goes out of scope, the element gets destructed).
When you don't want this behavior, you can use a vector of pointer or boost::ptr_vector instead.
Try this:
#include<iostream.h>
#include<vector.h>
class base
{
int i;
public:
base(int z=0){i=z;cout<<"okk constructor "<<i<<" called\n";}
base(const base& b1){i=b1.i;cout<<"copy constructor "<<i<<" called\n";}
void display(){cout<<" val is "<<i<<" \n";}
~base(){cout<<"destructor of "<<i<<" base called\n";}
};
int main()
{
cout<<"before anything\n";
vector<base> basev;
base baseobj1(1);
base baseobj2(2);
base baseobj3(3);
base baseobj4(4);
base baseobj5(5);
base baseobj6(6);
base baseobj7(7);
base baseobj8(8);
base baseobj9(9);
base baseobj10(10);
basev.push_back(baseobj1);
cout<<"second push back\n";
basev.push_back(baseobj2);
cout<<"third push back\n";
basev.push_back(baseobj3);
cout<<"fourth push back\n";
basev.push_back(baseobj4);
cout<<"fifth push back\n";
basev.push_back(baseobj5);
cout<<"sixth push back\n";
basev.push_back(baseobj6);
cout<<"seventh push back\n";
basev.push_back(baseobj7);
cout<<"eighth push back\n";
basev.push_back(baseobj8);
cout<<"ninth push back\n";
basev.push_back(baseobj9);
cout<<"10th push back\n";
basev.push_back(baseobj10);
cout<<"after all push back\n";
cout<<"before clear\n";
basev.clear();
cout<<"after clear\n";
}
output:
before anything
okk constructor 1 called
okk constructor 2 called
okk constructor 3 called
okk constructor 4 called
okk constructor 5 called
okk constructor 6 called
okk constructor 7 called
okk constructor 8 called
okk constructor 9 called
okk constructor 10 called
copy constructor 1 called
second push back
copy constructor 1 called
copy constructor 2 called
destructor of 1 base called
third push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
destructor of 1 base called
destructor of 2 base called
fourth push back
copy constructor 4 called
fifth push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
copy constructor 4 called
copy constructor 5 called
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
sixth push back
copy constructor 6 called
seventh push back
copy constructor 7 called
eighth push back
copy constructor 8 called
ninth push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
copy constructor 4 called
copy constructor 5 called
copy constructor 6 called
copy constructor 7 called
copy constructor 8 called
copy constructor 9 called
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
destructor of 5 base called
destructor of 6 base called
destructor of 7 base called
destructor of 8 base called
10th push back
copy constructor 10 called
after all push back
before clear
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
destructor of 5 base called
destructor of 6 base called
destructor of 7 base called
destructor of 8 base called
destructor of 9 base called
destructor of 10 base called
after clear
destructor of 10 base called
destructor of 9 base called
destructor of 8 base called
destructor of 7 base called
destructor of 6 base called
destructor of 5 base called
destructor of 4 base called
destructor of 3 base called
destructor of 2 base called
destructor of 1 base called
Yes pushing newRadio will push a copy of the Radio object into the vector. You also don't need to free the vector because it is local only so it will be destroyed once you are out of its scope. If for instance you wrote
vector<Radio> *m_radios = new vector<Radio>();
Then you would have to free that memory by calling the vector destructor manually.
std::vector
manages its own memory. That means that, when the destructor of a vector is invoked the memory held by the vector is released. std::vector
also invokes an object's destructor when it is removed (through erase
, pop_back
, clear
or the vector's destructor).
When you do this:
Radio newradio(radioNum);
m_radios.push_back(newradio);
You add a copy of newradio
(created using Radio
's copy constructor) to the vector. newradio
will be destroyed when it goes out of scope, and the copy will be destroyed when it is removed from the vector (as for any object).
That's an important point: std::vector
only stores copies of an object, which means the object must have a meaningful copy constructor (and an assignment operator, but that's another issue). If you have a vector of pointers, then the pointer itself will be copied, and not what it points to. Note that this behavior is the same for every standard container (like std::list
or std::set
).
As a rule of thumb, if you're not using pointers, then you don't have to worry about releasing the memory yourself.
In C++11, most standard containers (including vector
) have an emplace_back
method that constructs an object in place at the end of the container. It takes a bunch of parameters and calls the constructor that best matches those parameters (or fails if no such constructor exist), using said constructor to create the object, without any copy, at the end of the container. So, the above code could be rewritten as:
m_radios.emplace_back(radioNum); // construct a Radio in place,
// passing radioNum as the constructor argument
Also in C++11, containers are usually move aware, so they no longer require objects to be copiable: if they are movable, then the container will move its contents as required (such as during reallocations, for instance). Copiable types are still required if you want to copy the vector.
Yup, radioNum
will be copied into m_radios
. As long as you're not deallocating pointers when newradio.~Radio();
occurs (out of scope), it's OK. If m_radios
, or a subclass uses pointers, you'll need to make the switch to smart pointers (shared_ptr
).
When m_radios
goes out of scope, the destructor is automatically called, and all the stuff std::vector
holds is freed.
push_back()
will store a copy of its argument within the vector. As long as Radio
implements proper value semantics, there will be no problems with it.