简体   繁体   中英

Destructor gets called when I don't want it to

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

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.

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 (ie destroying) the elements in the vector, then allocating (ie 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().

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 (ie the standard's specification for vector does not make the guarantee you would need).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM