[英]How to manage shared object lifetimes with static casts?
I am new to C++ style casts, and need help in understanding how the code below works (this is some dummy code I wrote to understand things). 我是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";
}
It prints 它打印
Creating A
Creating B
Destroying A
End of inner scope
End of outer scope
Destroying B
Destroying A
My understanding: 我的理解:
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
Why do I get the first Destroying A
and what exactly is happening here?! 为什么我会得到第一个
Destroying A
以及这里到底发生了什么?! How can A be destroyed twice? 如何将A销毁两次?
If you make sure the output is flushed (by using std::endl
, for example), you get 如果您确保输出已刷新(例如,使用
std::endl
),则会得到
Creating A
创造A.
Creating B
创造B.
Destroying A
摧毁A.
End of inner scope
内部范围结束
End of outer scope
外部范围结束
Destroying B
摧毁B.
Destroying A
摧毁A.
the reason for the double delete of A
is that you are constructing a shared_ptr
from a raw pointer here: 两次删除
A
的原因是您要从此处的原始指针构造一个shared_ptr
:
std::shared_ptr<A> (static_cast<A*>(objectB.get()));
This shared_ptr
is completely independent of the first one, and has its own reference count. 这个
shared_ptr
完全独立于第一个,并且有自己的引用计数。 So when the scope ends, it attempts to delete the A
pointer it holds. 因此,当范围结束时,它会尝试删除它所持有的
A
指针。 If you had done this instead: 如果您这样做,则:
std::shared_ptr<A>{objectB};
then you wouldn't have encountered the problem. 那么您就不会遇到问题。 Note there is no need for a
static_cast
here. 请注意,此处不需要
static_cast
。
Note that A
should have a virtual
destructor. 请注意,
A
应该具有virtual
析构函数。 shared_ptr
has a clever destruction mechanism which means that this is not crucial in this example, but in general, if you are going to delete objects polymorphically, the base class must have a virtual destructor. shared_ptr
具有聪明的销毁机制,这意味着在此示例中这并不重要,但是通常,如果要多态删除对象,则基类必须具有虚拟析构函数。
Just in case it wasn't clear from juanchopanza's answer, this line 如果从juanchopanza的回答中不清楚这条线
std::shared_ptr<A> (static_cast<A*>(objectB.get()));
is incorrect and leads to undefined behavior. 是不正确的,导致未定义的行为。
The shared pointer you construct here just takes the pointer you give it. 您在此处构造的共享指针仅使用您提供的指针。 It has no idea that the object pointed to by that pointer is already owned by another smart pointer.
不知道该指针指向的对象已被另一个智能指针拥有。 Furthermore it doesn't know that the pointer points to a sub-object and that the pointer will need to be cast back to
B*
in order to be delete
d, because the static_cast
hides that information from it. 此外,它不知道指针指向一个子对象,并且该指针将需要被
static_cast
回B*
才能delete
d,因为static_cast
会将信息隐藏在其中。
To cast smart pointers you need a cast that understands and is integrated with smart pointers. 要投射智能指针,您需要一个能够理解并与智能指针集成在一起的演员表。 C++ has
std::static_pointer_cast
and std::dynamic_pointer_cast
for this purpose. 为此,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";
}
With this code the output of your program shows correct behavior: 使用此代码,程序的输出将显示正确的行为:
make A
make B
End of inner scope
End of outer scope
~B
~A
Of course in this particular case you don't need an explicit cast, because std::shared_ptr
can figure out legal up-casts and do them implicitly. 当然,在这种特殊情况下,您不需要显式转换,因为
std::shared_ptr
可以找出合法的转换并隐式执行。 You need std::static_pointer_cast
to do down-casts though: 你需要
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";
}
Thanks, one last thing, if I don't need objectB, is it safe to do
std::shared_ptr<A> objectA(new B());
谢谢,最后一件事,如果我不需要objectB,可以安全地执行
std::shared_ptr<A> objectA(new B());
??
Yes, this does happen to be safe. 是的,这确实是安全的。 The
shared_ptr<A>
constructor receives a B*
and knows enough to store the fact that when deletion occurs it will need to convert the A*
that it holds to B*
. shared_ptr<A>
构造函数接收B*
并且知道足以存储这样的事实:当发生删除时,它将需要将它保持的A*
转换为B*
。 This ensures that the object gets deleted correctly. 这可确保正确删除对象。
However, if you really want your types A
and B
to behave polymorphically then you should probably just make them polymorphic types by adding virtual destructors, and then you don't have to worry about how smart std::shared_ptr
is about this. 但是,如果您确实希望类型
A
和类型B
具有多态性,则应该通过添加虚拟析构函数使它们成为多态类型,然后不必担心std::shared_ptr
多么聪明。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.