[英]recreate(reassign) a std::shared_ptr or std::unique_ptr
[英]What is the rationale for the difference in destruction behavior between std::unique_ptr and std::shared_ptr?
來自http://en.cppreference.com/w/cpp/memory/unique_ptr :
如果
T
是某個基數B
派生類( sic ),那么std::unique_ptr<T>
可以隱式轉換為std::unique_ptr<B>
。 所得的默認刪除器std::unique_ptr<B>
將使用操作符刪除B
,導致未定義的行為除非的析構函數B
是虛擬的。 請注意,std::shared_ptr
行為不同:std::shared_ptr<B>
將對類型T
使用operator delete,並且即使B
的析構函數不是虛擬的,也將正確刪除所擁有的對象。
上面描述的破壞行為差異的理由是什么? 我最初的猜測是性能?
同樣有趣的是, std::shared_ptr<B>
如何能夠調用類型T
的析構函數,以防B
上的析構函數是非虛擬的,並且從std::shared_ptr<B>
的上下文中看不到它。 std::shared_ptr<B>
?
std::shared_ptr<X>
已經在原始B*
上有一堆開銷。
shared_ptr<X>
基本上維護了4件事。 它維護一個指向B
的指針,它保持兩個引用計數(一個“硬”引用計數,一個用於weak_ptr
的“軟”引用計數),它維護一個清理函數。
清理功能是shared_ptr<X>
表現不同的原因。 創建shared_ptr<X>
,會創建一個調用該特定類型的析構函數的函數,並將其存儲在shared_ptr<X>
管理的清理函數中。
更改托管類型( B*
變為C*
)時,清理功能保持不變。
因為shared_ptr<X>
需要管理引用計數,所以清理函數存儲的額外開銷是微不足道的。
對於unique_ptr<B>
,該類幾乎與原始B*
一樣便宜。 它保持零狀態而不是B*
,它的行為(在破壞時)歸結為if (b) delete b;
。 (是的, if (b)
是多余的,但優化器可以解決這個問題)。
為了支持cast-to-base和delete-as-derived,必須存儲額外的狀態,以便記住unique_ptr
實際上是派生類。 這可以是存儲的指向刪除指針的形式,如shared_ptr
。
但是,這將使unique_ptr<B>
的大小加倍,或者要求它將數據存儲在堆上的某個地方。
決定unique_ptr<B>
應該是零開銷,因此它仍然不支持cast-to-base同時仍然調用base的析構函數。
現在,你可以通過簡單地添加一個刪除器類型並存儲一個知道它正在銷毀的東西類型的銷毀函數來教導unique_ptr<B>
這樣做。 上面一直在談論unique_ptr
的默認刪除,這是無狀態和無關緊要的。
struct deleter {
void* state;
void(*f)(void*);
void operator()(void*)const{if (f) f(state);}
deleter(deleter const&)=default;
deleter(deleter&&o):deleter(o) { o.state = nullptr; o.f=nullptr; }
deleter()=delete;
template<class T>
deleter(T*t):
state(t),
f([](void*p){delete static_cast<T*>(p);})
{}
};
template<class T>
using smart_unique_ptr = std::unique_ptr<T, deleter>;
template<class T, class...Args>
smart_unique_ptr<T> make_smart_unique( Args&&... args ) {
T* t = new T(std::forward<Args>(args)...);
return { t, t };
}
實例 ,我生成一個unique-ptr派生,將它存儲在unique-ptr to base中,然后重置base。 派生指針被刪除。
(一個簡單的void(*)(void*)
deleteter可能會遇到問題,因為傳入的void*
在基本和派生的情況之間的值會有所不同。)
請注意,更改存儲在此unique_ptr
的指針而不更改刪除操作將導致不正常的行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.