簡體   English   中英

如何使用靜態強制轉換來管理共享對象的生命周期?

[英]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_castB*才能delete d,因為static_cast會將信息隱藏在其中。

要投射智能指針,您需要一個能夠理解並與智能指針集成在一起的演員表。 為此,C ++具有std::static_pointer_caststd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM