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):
My guess is that the Deleter had to be CopyConstructible really only as a
relic of C++03 where move semantics didn’t exist.Your guess is correct. When
shared_ptrwas 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);throws,
dmust be left intact for the cleanupd(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 thenewthrows,dwill be left
in its original state.If we go further and allow
Dto have a throwing move constructor, things get
more complicated. But we won’t. 🙂