为什么shared_ptr删除程序必须是CopyConstructible的? [英] Why do shared_ptr deleters have to be CopyConstructible?
问题描述
在C ++ 11中,std::shared_ptr
具有四个构造函数,可以将其传递给类型为D
的删除对象d
.这些构造函数的签名如下:
In C++11 std::shared_ptr
has four constructors which can be passed deleter objects d
of type D
. The signatures of these constructors are the following:
template<class Y, class D> shared_ptr(Y * p, D d);
template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);
template <class D> shared_ptr(nullptr_t p, D d);
template <class D, class A> shared_ptr(nullptr_t p, D d, A a);
该标准要求 [util.smartptr.shared.const] 类型D
是可复制构造的.为什么需要这个?如果shared_ptr
复制了d
,那么这些删除器中的哪个会被调用? shared_ptr
不可能只保留一个删除器吗?如果可以复制d
,shared_ptr
拥有删除器是什么意思?
The standard requires in [util.smartptr.shared.const] type D
to be CopyConstructible. Why is this needed? If shared_ptr
makes copies of d
then which of these deleters might get called? Wouldn't it possible for a shared_ptr
only to keep a single deleter around? What does it mean for a shared_ptr
to own a deleter if d
can be copied?
CopyConstructible要求背后的原理是什么?
PS:此要求可能会使shared_ptr
的编写删除程序变得复杂. unique_ptr
似乎对其删除器有更好的要求.
PS: This requirement might complicate writing deleters for shared_ptr
. unique_ptr
seems to have much better requirements for its deleter.
推荐答案
这个问题非常令人困惑,以至于我通过电子邮件发送给Peter Dimov(boost::shared_ptr
的实现者,并参与了std::shared_ptr
的标准化工作)
This question was perplexing enough that I emailed Peter Dimov (implementer of boost::shared_ptr
and involved in standardization of std::shared_ptr
)
以下是他所说的内容(经他的许可转载):
Here's the gist of what he said (reprinted with his permission):
我的猜测是,Deleter实际上必须是CopyConstructible的,因为 C ++ 03的遗物,其中不存在移动语义.
My guess is that the Deleter had to be CopyConstructible really only as a relic of C++03 where move semantics didn’t exist.
您的猜测是正确的.当指定shared_ptr
时,右值引用
还不存在.如今,我们应该能够满足要求
无需移动即可构建.
Your guess is correct. When shared_ptr
was specified rvalue references
didn't exist yet. Nowadays we should be able to get by with requiring
nothrow move-constructible.
在什么时候有一个微妙之处
There is one subtlety in that when
pi_ = new sp_counted_impl_pd<P, D>(p, d);
抛出,必须完全保留d
才能使清理d(p)
正常工作,但是我
认为这将不是问题(尽管我实际上并没有
试图使实现易于移动).
[...]
我认为对于
实现对其进行定义,以便在抛出new
时将保留d
保持其原始状态.
throws, d
must be left intact for the cleanup d(p)
to work, but I
think that this would not be a problem (although I haven't actually
tried to make the implementation move-friendly).
[...]
I think that there will be no problem for the
implementation to define it so that when the new
throws, d
will be left
in its original state.
如果我们走得更远并且允许D
具有投掷移动构造函数,事情将会变得
更复杂.但是我们不会. :-)
If we go further and allow D
to have a throwing move constructor, things get
more complicated. But we won't. :-)
这篇关于为什么shared_ptr删除程序必须是CopyConstructible的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!