Reputation: 3417
The destructor of the class I made gets called before the end of scope. I think that it has something to do with the reallocation in the vector when I add another element to it. How to I surpass this issue? I want the destructor to be called only when the object reaches the end of scope in my code.
#include <string>
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
~A() { cout << "destructor called\n"; }
};
int main ()
{
A one, two;
vector<A> vec;
cout << "push_back one" << endl;
vec.push_back(one);
cout << "push_back two" << endl;
vec.push_back(two);
//destructor gets called here
system("pause");
return 0;
} //while i want it to be called here
Upvotes: 3
Views: 334
Reputation: 1736
According to the C++ Standard § 23.3.6:
Vectors have a specific capacity, meaning
The total number of elements that the vector can hold without requiring reallocation
When you push_back
an additional element, this effectively increases the container size by one, which
Causes reallocation if the new size is greater than the old capacity
Re-allocation implies that you are de-allocating (i.e. destroying) the elements in the vector, then allocating (i.e. constructing) them again.
Note that, in your case, the original one
and two
instances of A
are not destroyed, rather their copies which are stored in the vector are.
A programmer needs to be more careful with references and iterators though, because
Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence.
As others have mentioned, reserve()
will help prevent this, because
No reallocation shall take place during insertions that happen after a call to reserve() until the time when an insertion would make the size of the vector greater than the value of capacity().
Upvotes: 2
Reputation: 104698
As the comments suggest, you should use std::vector<>::reserve(size_t)
.
What you are seeing is implementation defined. Most implementations approximately double the reserved allocation size when growing. This is to avoid making many allocations and copies whenever the size grows.
Reserving simply suggests to the collection that you will need n elements. The implementation, if it chooses to honor the request, reallocates and moves/copies the existing values to the new allocation which is large enough to hold the number of elements you've requested. Now you can push back without costly reallocation. Reserving properly can save you many reallocations as the container is resized, when you have a good idea what the final size will be.
Reserving in this case would avoid that resize, and the destruction of the temporary you see.
You see the destructor likely because the collection is resizing. As you push back the second time, it reallocates.
If the object must never be destroyed, you should consider another collection type or storage location, since the program in its present form relies on implementation-defined behavior (i.e. the standard's specification for vector does not make the guarantee you would need).
Upvotes: 1
Reputation: 726569
Printouts in your code do not show you the complete picture: the destructor is called for a different object.
Take a look at this modified code. I added printouts of the address, and logging in some other key places, such as calls of the assignment operator and copy constructor.
#include <string>
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
A() {cout << "constructed " << (void*)this << "\n";}
A(const A& a) {cout << "copied " << (void*)(&a) << " to " << (void*)this << "\n"; }
A& operator =(const A& a) {cout << "assigned " << (void*)(&a) << " to " << (void*)this << "\n"; }
~A() { cout << "destructor called for " << (void*)this << "\n"; }
};
int main ()
{
A one, two;
vector<A> vec;
cout << "push_back one" << endl;
vec.push_back(one);
cout << "push_back two" << endl;
vec.push_back(two);
//destructor gets called here
return 0;
}
It produces the following output (demo):
constructed 0xbff229b2
constructed 0xbff229b3
push_back one
copied 0xbff229b2 to 0x970c008
push_back two
copied 0xbff229b3 to 0x970c019
copied 0x970c008 to 0x970c018
destructor called for 0x970c008
destructor called for 0x970c018
destructor called for 0x970c019
destructor called for 0xbff229b3
destructor called for 0xbff229b2
You can see that objects one
and two
(0xbff229b2
and 0xbff229b3
) do not get destroyed until the end, when they go out of scope. Its their copies that get destroyed when the vector is resized.
Upvotes: 3