为什么 std::shared_ptr 在使用 std::static_pointer_cast 时会破坏两次?

Why std::shared_ptr destruct twice when used std::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);
    b->push_back(A{});
    return 0;
}

它打印:

ccccdddddddd

表示析构函数被调用两次。为什么会发生这种情况以及如何解决?

析构函数调用是 b->push_back(A{}); 而不是 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;
}

显示 cccddd

调用额外析构函数的原因是,向量可能需要在 push_back 上增加其容量,完成后可能需要 move/copy 现有元素到新元素位置,并因此删除旧元素。所以你看到的额外的析构函数是这个的结果。

在您的情况下,copy/move 构造已默认创建。如果您手动定义它们并向其添加日志记录,您可以看到它们匹配。

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

防止它的唯一方法是创建容量足够大的向量以容纳您要保存的所有元素。

没有什么可以解决的。每个对象的析构函数不会被调用两次。相反,您并没有跟踪所有的构造函数。向复制和移动构造函数添加跟踪,如

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

进行此更改后,您的输出应该是

ccccMCCCdddddddd

表示 8 次构造函数调用和 8 次析构函数调用。