如何使用静态强制转换来管理共享对象的生命周期?

Laz*_*zer 2 c++ shared-ptr static-cast c++11

我是C++样式演员的新手,需要帮助理解下面的代码是如何工作的(这是我写的一些虚拟代码来理解事物).

#include <iostream>
#include <memory>

class A { 
public:
    A() : a(1) {
        std::cout << "Creating A\n";
    }   
    ~A() {
        std::cout << "Destroying A\n";
    }   
    int a;
};

class B : public A { 
public:
    B() : b(2) {
        std::cout << "Creating B\n";
    }   
    ~B() {
        std::cout << "Destroying B\n";
    }   
    int b;
};

int main() {
    std::shared_ptr<B> objectB(new B());
    {   
    std::shared_ptr<A> (static_cast<A*>(objectB.get()));
    std::cout << "End of inner scope\n";
    }   
    std::cout << "End of outer scope\n";
}
Run Code Online (Sandbox Code Playgroud)

它打印

Creating A
Creating B
Destroying A
End of inner scope
End of outer scope
Destroying B
Destroying A
Run Code Online (Sandbox Code Playgroud)

我的理解:

Creating A         -> B's ctor calls base class ctor
Creating B         -> B's ctor
Destroying A       -> ???
End of inner scope
End of outer scope
Destroying B       -> B's dtor
Destroying A       -> B's dtor calls base dtor
Run Code Online (Sandbox Code Playgroud)

为什么我会得到第一个Destroying A以及到底发生了什么?!A怎么能被摧毁两次?

jua*_*nza 6

如果确保输出已刷新(std::endl例如,使用),则得到

创造A.

创造B.

摧毁A.

内部范围结束

外部范围结束

摧毁B.

摧毁A.

双重删除的原因A是你在shared_ptr这里构建一个原始指针:

std::shared_ptr<A> (static_cast<A*>(objectB.get()));
Run Code Online (Sandbox Code Playgroud)

shared_ptr完全独立于第一个,并有自己的引用计数.因此,当范围结束时,它会尝试删除A它所持有的指针.如果你这样做了:

std::shared_ptr<A>{objectB};
Run Code Online (Sandbox Code Playgroud)

那么你就不会遇到这个问题.注意这里没有必要static_cast.

请注意,A应该有一个virtual析构函数.shared_ptr有一个聪明的破坏机制,这意味着这在这个例子中并不重要,但一般来说,如果要以多态方式删除对象,基类必须有一个虚拟析构函数.