[英]How can unique_ptr have no overhead if it needs to store the deleter?
首先看一下C ++ Primer關於unique_ptr
和shared_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>
很可能是零開銷(任何理智的標准庫實現)。 對於任意D
, std::unique_ptr<T, D>
通常不是零開銷。
原因很簡單:如果刪除器是空的(因此是無狀態的)類型(例如std::default_delete
instantiations),則可以使用Empty-Base Optimization來消除刪除器的存儲。
似乎讓你困惑的關鍵詞是“刪除器可以直接存儲”。 但是存儲類型為std::default_delete
的刪除器沒有意義。 如果你需要一個,你可以創建一個std::default_delete{}
。
通常,無需存儲無狀態刪除程序,因為您可以按需創建它們。
簡介:
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.