![](/img/trans.png)
[英]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.