Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't this object being destroyed?

I have spending ages trying to figure out why this is happening.

  struct Element
    {
        Element(int number) : number_ID(number) 
        { std::cout << "Element number " << number_ID << " is being constructed\n"; }
        ~Element() 
        { std::cout << "Element number " << number_ID << " is being destroyed\n"; }
        int number_ID;
    };

    void createVector()
    {
        std::vector<Element> objArr;
        objArr.reserve(10);        // So it doesn't have to reallocate

        objArr.emplace_back(1);
        objArr.emplace_back(2);
        objArr.emplace_back(3);
        objArr.emplace_back(4);

        objArr.erase(objArr.begin());      // When I erase the first element only element 4 has destructor called
    }

    int main()
    {
        createVector();


        system("pause");
    }

I get:

Element number 1 is being constructed
Element number 2 is being constructed
Element number 3 is being constructed
Element number 4 is being constructed
//The following called when doing objArr.erase(objArr.begin());
Element number 4 is being destroyed
//The following called after createVector() function exits
Element number 2 is being destroyed
Element number 3 is being destroyed
Element number 4 is being destroyed

The destructor for Element 1 never gets called? At first I didn't know why Element number 4 destructor would get called when erasing the first element, and then I thought when it shifts its members maybe the destructor has to get called. But the documentation says that all of the members after the one deleted get shifted, and the destructors of 2 and 3 didn't get called. I am really confused.

EDIT: Well if this is an optimisation step, then the documentation is wrong, because:

Removes from the vector either a single element (position) or a range of elements ([first,last)).

This effectively reduces the container size by the number of elements removed, which are destroyed.

That's not destroying then.

like image 905
Zebrafish Avatar asked Jan 26 '17 03:01

Zebrafish


1 Answers

vector is trying to save performance.

What erase does is it copies elements 2, 3 and 4 down one element, overwriting the element containing 1. So the first element now contains 2, etc. Then it destroys the last element, which is a copy of 4.

That has the effect of erasing the first element, but not quite in the way you thought it would. It erases the contents of the first element, but not the object itself.

Depending on the type you store in your vector, this will be less expensive than destroying the first element, only to reconstruct a copy of the second element in the storage of the first.

Well if this is an optimisation step, then the documentation is wrong, because:

...

That's not destroying then.

The documentation is correct, and it is destroying them.

Your objects are the values they contain. You declared that your classes were copyable, so vector is free to copy them. That means it's perfectly legitimate for two instances to have the same value. vector exploits that.

If you had made your classes non-copyable but noexcept moveable, then it would work correctly. But your move constructor would also need to null-out the moved-from object, so that no two instances would have the same value.

like image 58
Nicol Bolas Avatar answered Oct 21 '22 06:10

Nicol Bolas