Xiaodong Liu
Xiaodong Liu

Reputation: 57

Why std::shared_ptr destruct twice when used std::static_pointer_cast?

my code is as below:

#include <iostream>
#include <memory>
#include <vector>
using namespace std;


struct A {
    A() { cout << "c"; }
    ~A() { cout << "d"; }
};

int main() {
    shared_ptr<void> a = make_shared<vector<A>>(3);
    auto b = static_pointer_cast<vector<A>>(a);
    b->push_back(A{});
    return 0;
}

It prints:

ccccdddddddd

which indicates that the destructor is called twice. Why this happens and how to fix it?

Upvotes: 0

Views: 120

Answers (2)

t.niese
t.niese

Reputation: 40842

The destructor calls is the result of b->push_back(A{}); and not of the static_pointer_cast

#include <iostream>
#include <memory>
#include <vector>
using namespace std;


struct A {
    A() { cout << "c"; }
    ~A() { cout << "d"; }
};

int main() {
    shared_ptr<void> a = make_shared<vector<A>>(3);
    auto b = static_pointer_cast<vector<A>>(a);

    return 0;
}

shows cccddd.

The reason for the additional destructor calls is, because a vector might need to increase its capacity on a push_back and when this is done it might need to move/copy the existing elements to a new location, and due to that delete the old elements. So the additional destructors that you see are the result of this.

In your case the copy/move constructs have been created by default. If you manually define them and add logging to it, you can see that they match up.

struct A {
    A() { cout << "c"; }
    A(const A&)  { cout << "C"; };
    A(A&&)  { cout << "M"; };
    ~A() { cout << "d"; }
};

The only way to prevent it is to create the vector with a capacity that is large enough to hold all elements that you want to save in it.

Upvotes: 1

JaMiT
JaMiT

Reputation: 16843

There is nothing to fix. The destructor is not being called twice per object. Rather, you are not tracking all of the constructors. Add tracking to the copy and move constructors, as in

struct A {
    A() { cout << "c"; }
    A(const A &) { cout << "C"; }
    A(A &&) { cout << "M"; }
    ~A() { cout << "d"; }
};

With this change, your output should be

ccccMCCCdddddddd

indicating 8 constructor calls and 8 destructor calls.

Upvotes: 2

Related Questions