The destructor is called when I don't want it

The destructor of the class I created is called to the end of the scope. I think it has something to do with the reallocation in the vector when I add another element to it. How can I go beyond this question? I want the destructor to be called only when the object reaches the end of the 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

      

+3


source to share


3 answers


The printouts in your code do not show the complete image: the destructor is called on another object.

Take a look at this modified code. I have added address printouts and enter some other key places like assignment operator calls 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 outputs 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 the objects one

and two

( 0xbff229b2

and 0xbff229b3

) are not completely destroyed when they go out of bounds. Its copies, which are destroyed when the vector is resized.

+3


source


According to C ++ standard Β§ 23.3.6:

Vectors have a certain capacity, which means

The total number of elements that a vector can hold without the need for reallocation

When you push_back

add an item, it actually increases the container size by one, which is

Causes redistribution if the new size is larger than the old capacity

Reallocation means that you de-select (i.e. destroy) the elements in the vector and then select (i.e. construct) them again.



Please note that in your case the original one

and the two

instances are A

not destroyed, rather their copies, which are stored in the vector.

The programmer needs to be more careful with references and iterators, because

The reallocation invalidates all references, pointers, and iterators that refer to elements in the sequence.

As mentioned, reserve()

will help prevent this because

Reallocation should not occur during insertions that occur after a call to reserve () until the insertion makes the vector size larger than the capacity () value.

+2


source


As the comments suggest, you should be using std::vector<>::reserve(size_t)

.

What you see is the implementation. Most implementations roughly double the allocated allocation size as they grow. This is done in order to avoid many allocations and copies whenever the size increases.

The reservation simply suggests the collections that you need n items. The implementation, if it decides to execute the request, reallocates and moves / copies the existing values ​​into a new distribution that is large enough to hold the number of items requested. You can now come back without costly reallocation. Proper reservations can save you a lot of reallocations when resizing the container when you have a good idea what the final size will be.

Reserving in this case will avoid resizing and destroying the temporary image that you see.

You are probably seeing the destructor because the collection is resized. When you release a second time, it redistributes.

If the object should never be destroyed, you should consider a different type of collection or storage location, since the program as it stands depends on implementation-defined behavior (that is, the standard specification for a vector does not provide the guarantee you need).

+1


source







All Articles