簡體   English   中英

父類使用默認構造函數; 子類的析構函數被意外調用

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

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