[英]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.