[英]Parent class using default constructor; child class' destructor is unexpectedly called
我在C ++中有一個方案,在我沒有想到的情況下會調用子級的析構函數。 最小再現如下:
#include <cstdio>
#include <memory>
using namespace std;
class Parent {
public:
};
class Child : public Parent {
public:
~Child() {
printf("Got here\n");
}
};
int
main()
{
shared_ptr<Parent> x(new Child);
}
通常,類似這樣的錯誤。 開發人員打算調用子析構函數,並且正確的操作是將一個空的虛擬析構函數插入父函數。 然而,讓我震驚,無論是G ++ 4.4.7(是的,我知道這是老)和鐺3.4.2編譯這使得孩子的析構函數被調用。
這符合標准嗎?
好吧,即使shared_ptr
沒有特殊的魔力,使用具有非虛擬析構函數的父指針delete
ing也是未定義的行為,因此(調用子析構函數的)結果肯定是一致的。
但是在這種情況下, shared_ptr
“記住”您傳遞給它的原始對象的類型,並通過子指針(通過其存儲的刪除器)銷毀它。
一個獨特的ptr會在這里搞砸。 但是共享的ptr在這里確實有些“神奇”。
shared_ptr<T> has two things they manage; the
shared_ptr<T> has two things they manage; the
T *`和參考計數塊。
引用計數塊包含兩個atomic<std::size_t>
,一個用於強引用,一個用於弱引用,以及一個類型擦除的刪除器。 這個std::function
的類型擦除的刪除器會記住如何刪除您擁有的東西。
當您使用U*u
構造任何shared_ptr
時,默認情況下,它將[u]{std::default_delete<U>{}(u);}
在該刪除器中。
實際上,它記住如何根據傳入的類型刪除對象。
shared_ptr
非常靈活。
您可以傳入自定義刪除器以替換默認的刪除器,可以使用別名構造函數從存儲的T*
拆分使用的引用計數塊,可以使用make_shared
在同一內存分配中分配引用計數塊和T
。
引用計數塊的開銷是為什么它存儲刪除器。 考慮到我們仍然需要該塊,因此它並沒有被認為過於昂貴。 相比之下,默認情況下unique_ptr
不會執行任何操作; 您必須顯式添加一個刪除程序,並且如果需要,必須管理shared_ptr默認為您執行的所有花哨技巧。 unique_ptr
在原始擁有指針上的開銷基本上為零; shared_ptr
具有顯着的開銷,但是與內存分配開銷相比通常很小。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.