[英]C++ Rule of Zero : polymorphic deletion and unique_ptr behavior
在最近實施零規則主題下的超載期刊中 ,作者描述了我們如何避免編寫五個操作符規則,因為編寫它們的原因是:
這兩個都可以通過使用智能指針來處理。
在這里,我對第二部分特別感興趣。
請考慮以下代碼段:
class Base
{
public:
virtual void Fun() = 0;
};
class Derived : public Base
{
public:
~Derived()
{
cout << "Derived::~Derived\n";
}
void Fun()
{
cout << "Derived::Fun\n";
}
};
int main()
{
shared_ptr<Base> pB = make_shared<Derived>();
pB->Fun();
}
在這種情況下,正如文章的作者解釋的那樣,我們通過使用共享指針獲得多態刪除,這確實有效。
但是,如果我用unique_ptr
替換shared_ptr
,我將無法再觀察到多態刪除。
現在我的問題是,為什么這兩種行為有所不同? 為什么shared_ptr
會處理多態刪除,而unique_ptr
卻沒有?
如果您使用C ++ 14 make_unique
或在Yakk的答案中編寫自己的一個,它將起作用。 基本上,共享指針行為之間的區別在於:
template<
class T,
class Deleter = std::default_delete<T>
> class unique_ptr;
對於unique_pointer
並且如您所見,刪除器屬於該類型。 如果聲明unique_pointer<Base>
它將始終使用std::default_delete<Base>
作為默認值。 但make_unique
將負責為您的班級使用正確的刪除器。
使用shared_ptr
你得到:
template< class Y, class Deleter >
shared_ptr( Y* ptr, Deleter d );
和其他重載作為構造函數。 正如您所看到的, unique_ptr
的默認刪除器在聲明類型時取決於模板參數(除非您使用make_unique
),而對於shared_ptr
,刪除器取決於傳遞給構造函數的類型。
你可以看到一個允許在沒有虛擬析構函數的情況下進行多態刪除的版本(這個版本也適用於VS2012)。 請注意,它有點被黑客攻擊,我目前還不確定在C ++ 14中unique_ptr
和make_shared
的行為是什么樣的,但我希望它們能讓這更容易。 也許我會查看有關C ++ 14新增內容的論文,看看如果我以后有空的話會有什么變化。
你有答案: https : //stackoverflow.com/a/22861890/2007142
引用:
一旦最后一次引用
shared_ptr
超出范圍或被重置,將調用~Derived()
並釋放內存。 因此,您不需要將~Base()
虛擬化。unique_ptr<Base>
和make_unique<Derived>
不提供此功能,因為它們不提供shared_ptr
相對於刪除器的機制,因為唯一指針更簡單並且旨在實現最低開銷,因此不存儲額外的刪除程序所需的函數指針。
template<typename T>
using smart_unique_ptr=std::unique_ptr<T,void(*)(void*)>;
template<class T, class...Args> smart_unique_ptr<T> make_smart_unique(Args&&...args) {
return {new T(std::forward<Args>(args)...), [](void*t){delete (T*)t;}};
}
問題是unique_ptr
的默認刪除器調用存儲指針上的delete
。 上面存儲了一個知道構造類型的刪除器,因此當復制到基類時, unique_ptr
仍將作為子類刪除。
這增加了適度的開銷,因為我們必須取消引用指針。 此外,它smart_unique_ptr
類型進行非規范化,因為默認構造的smart_unique_ptr
現在是非法的。 您可以通過一些額外的工作來解決這個問題(用至少不會崩潰的半智能仿函數替換原始函數指針:但是,如果在調用刪除器時unique
非空,則應該聲明函數指針存在) 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.