[英]How to manage shared object lifetimes with static casts?
我是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";
}
它打印
Creating A
Creating B
Destroying A
End of inner scope
End of outer scope
Destroying B
Destroying A
我的理解:
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
为什么我会得到第一个Destroying A
以及这里到底发生了什么?! 如何将A销毁两次?
如果您确保输出已刷新(例如,使用std::endl
),则会得到
创造A.
创造B.
摧毁A.
内部范围结束
外部范围结束
摧毁B.
摧毁A.
两次删除A
的原因是您要从此处的原始指针构造一个shared_ptr
:
std::shared_ptr<A> (static_cast<A*>(objectB.get()));
这个shared_ptr
完全独立于第一个,并且有自己的引用计数。 因此,当范围结束时,它会尝试删除它所持有的A
指针。 如果您这样做,则:
std::shared_ptr<A>{objectB};
那么您就不会遇到问题。 请注意,此处不需要static_cast
。
请注意, A
应该具有virtual
析构函数。 shared_ptr
具有聪明的销毁机制,这意味着在此示例中这并不重要,但是通常,如果要多态删除对象,则基类必须具有虚拟析构函数。
如果从juanchopanza的回答中不清楚这条线
std::shared_ptr<A> (static_cast<A*>(objectB.get()));
是不正确的,导致未定义的行为。
您在此处构造的共享指针仅使用您提供的指针。 不知道该指针指向的对象已被另一个智能指针拥有。 此外,它不知道指针指向一个子对象,并且该指针将需要被static_cast
回B*
才能delete
d,因为static_cast
会将信息隐藏在其中。
要投射智能指针,您需要一个能够理解并与智能指针集成在一起的演员表。 为此,C ++具有std::static_pointer_cast
和std::dynamic_pointer_cast
。
int main() {
std::shared_ptr<B> objectB(new B());
{
std::shared_ptr<A> x = std::static_pointer_cast<A>(objectB);
std::cout << "End of inner scope\n";
}
std::cout << "End of outer scope\n";
}
使用此代码,程序的输出将显示正确的行为:
make A
make B
End of inner scope
End of outer scope
~B
~A
当然,在这种特殊情况下,您不需要显式转换,因为std::shared_ptr
可以找出合法的转换并隐式执行。 你需要std::static_pointer_cast
进行向下转换:
int main() {
std::shared_ptr<A> objectA(new B());
{
std::shared_ptr<B> x = std::static_pointer_cast<B>(objectA);
std::cout << "End of inner scope\n";
}
std::cout << "End of outer scope\n";
}
谢谢,最后一件事,如果我不需要objectB,可以安全地执行
std::shared_ptr<A> objectA(new B());
?
是的,这确实是安全的。 shared_ptr<A>
构造函数接收B*
并且知道足以存储这样的事实:当发生删除时,它将需要将它保持的A*
转换为B*
。 这可确保正确删除对象。
但是,如果您确实希望类型A
和类型B
具有多态性,则应该通过添加虚拟析构函数使它们成为多态类型,然后不必担心std::shared_ptr
多么聪明。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.