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).
#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?! How can A be destroyed twice?
If you make sure the output is flushed (by using std::endl
, for example), you get
Creating A
Creating B
Destroying A
End of inner scope
End of outer scope
Destroying B
Destroying A
the reason for the double delete of A
is that you are constructing a shared_ptr
from a raw pointer here:
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. So when the scope ends, it attempts to delete the A
pointer it holds. 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.
Note that A
should have a virtual
destructor. 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.
Just in case it wasn't clear from juanchopanza's answer, this line
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.
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.
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. You need std::static_pointer_cast
to do down-casts though:
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());
?
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*
. 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.