![](/img/trans.png)
[英]C++ Initialize std::vector<std::unique_ptr<Base>> in derived classes
[英]Deleting derived classes in std::unique_ptr<Base> containers
我有點困惑。 基本上,我有兩個不同的資源管理器(AudioLibrary和VideoLibrary),它們都從共享的BaseLibrary類繼承。 此基類包含對音頻和視頻的引用。 音頻和視頻都從名為Media的父類繼承。
我將數據保存在地圖中,填充了unique_ptr。 但令我驚訝的是,我發現當這些指針最終通過.erase被刪除時,只調用了Media的基本析構函數。
我想我錯過了一些東西,但我認為編譯器/運行時庫會知道它指向視頻或音頻並將其稱為析構函數。
似乎並非如此。 我被迫做這樣的事情來實際收回我的所有資源:
void AudioLibrary::deleteStream( const std::string &pathFile )
{
auto baseStream = mStreams[ pathFile ].release();
mStreams.erase( pathFile );
// Re-cast!
auto aStream = static_cast<AudioStream*>( baseStream );
delete aStream;
}
這是正常的行為嗎?
更新:
你沒事 - 當然這是析構函數缺失的'虛擬'。 我想我最近剛想到的虛擬和繼承意味着什么越來越少,有點讓我的頭腦失去其功能,而不是概念本身。 偶爾會發生在我身上。
unique_ptr<T>
的默認刪除器是恰當命名的default_delete<T>
。 這是一個無狀態函子,在其T *
參數上調用delete
。
如果希望在銷毀基類的unique_ptr
時調用正確的析構函數,則必須使用虛擬析構函數,或者在刪除器中捕獲派生類型。
您可以使用函數指針刪除器和無捕獲的lambda輕松完成此操作:
std::unique_ptr<B, void (*)(B *)> pb
= std::unique_ptr<D, void (*)(B *)>(new D,
[](B *p){ delete static_cast<D *>(p); });
當然,這意味着您需要將刪除器的模板參數添加到unique_ptr
所有用途中。 將其封裝在另一個類中可能更優雅。
另一種方法是使用shared_ptr
,因為它確實捕獲派生類型,只要您使用std::shared_ptr<D>(...)
創建派生的shared_ptr
或者最好是std::make_shared<D>(...)
這是因為您尚未將Media
析構函數聲明為virtual
。 如您所見,如果您這樣做,例如:
struct Media {
virtual ~Media() = default;
};
struct AudioLibrary : Media {};
struct VideoLibrary : Media {};
int main() {
std::map<int, std::unique_ptr<Media>> map;
map[0] = std::unique_ptr<Media>(new AudioLibrary());
map[1] = std::unique_ptr<Media>(new VideoLibrary());
}
兩個析構函數都將被調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.