簡體   English   中英

如果需要存儲刪除器,unique_ptr怎么沒有開銷?

[英]How can unique_ptr have no overhead if it needs to store the deleter?

首先看一下C ++ Primer關於unique_ptrshared_ptr
$ 16.1.6。 效率和靈活性

我們可以確定shared_ptr不將刪除器保存為直接成員,因為直到運行時才知道刪除器的類型。

因為刪除器的類型是unique_ptr類型的一部分,所以刪除器成員的類型在編譯時是已知的。 刪除器可以直接存儲在每個unique_ptr對象中。

所以似乎shared_ptr沒有刪除器的直接成員,但unique_ptr確實如此。 然而, 另一個問題的最高投票回答說:

如果您將deleter作為模板參數提供(如在unique_ptr ),則它是該類型的一部分,您不需要在此類型的對象中存儲任何其他內容 如果將deleteter作為構造函數的參數傳遞(如在shared_ptr,則需要將其存儲在對象中 這是額外靈活性的代價,因為您可以為相同類型的對象使用不同的刪除器。

引用的兩段完全相互矛盾,讓我感到困惑。 更重要的是, 許多人說unique_ptr是零開銷,因為它不需要將刪除器存儲為成員。 但是,正如我們所知, unique_ptr有一個unique_ptr<obj,del> p(new obj,fcn)的構造函數,這意味着我們可以向它傳遞一個刪除器,因此unique_ptr似乎已將刪除器存儲為成員。 真是一團糟!

std::unique_ptr<T>很可能是零開銷(任何理智的標准庫實現)。 對於任意Dstd::unique_ptr<T, D>通常不是零開銷。

原因很簡單:如果刪除器是空的(因此是無狀態的)類型(例如std::default_delete instantiations),則可以使用Empty-Base Optimization來消除刪除器的存儲。

似乎讓你困惑的關鍵詞是“刪除器可以直接存儲”。 但是存儲類型為std::default_delete的刪除器沒有意義。 如果你需要一個,你可以創建一個std::default_delete{}

通常,無需存儲無狀態刪除程序,因為您可以按需創建它們。

Angew的回答非常徹底地解釋了發生了什么。

對於那些好奇的事情,看起來如何

template<typename T, typename D, bool Empty = std::is_empty_v<D>>
class unique_ptr
{
    T* ptr;
    D d;

    // ... 
};

template<typename T, typename D>
class unique_ptr<T, D, true> : D
{
    T* ptr;

    // ...
};

其中專門用於空刪除並利用空基優化

簡介:

unique_ptr 可以引入一些小的開銷,但不是因為刪除,而是因為當你從它移動時,value必須設置為null,如果你使用原始指針,你可以將舊指針留在容易出錯但合法的狀態,它仍然指向它指向的地方。 顯然智能優化器可以優化,但不能保證。

回到刪除者:

其他答案是正確的,但詳細說明。 所以這里是簡化版本,沒有提到EBO或其他復雜的術語。

如果deleter為空(沒有狀態),則不需要將其保留在unique_ptr中。 如果您需要它,您可以在需要時構建它。 您需要知道的是刪除類型(這是unique_ptr的模板參數之一)。

對於exaple,請考慮以下代碼,而不是演示無狀態對象的簡單創建。

#include <iostream>
#include <string>
#include <string_view>

template<typename Person>
struct Greeter{
    void greet(){
        static_assert(std::is_empty_v<Person>, "Person must be stateless");
        Person p; // Stateless Person instance constructed on demand
        std::cout << "Hello " << p() << std::endl;
    }
    // ... and not kept as a member.
};

struct Bjarne{
    std::string_view operator()(){
        return "Bjarne";
    }
};

int main() {
    Greeter<Bjarne> hello_bjarne;
    hello_bjarne.greet();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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