2685. shared_ptr deleters must not not throw on move construction

Section: 23.11.3.1 [util.smartptr.shared.const] Status: C++17 Submitter: Jonathan Wakely Opened: 2016-05-03 Last modified: 2017-07-30

Priority: 0

View all other issues in [util.smartptr.shared.const].

View all issues with C++17 status.

Discussion:

In 23.11.3.1 [util.smartptr.shared.const] p8 the shared_ptr constructors taking a deleter say:

The copy constructor and destructor of D shall not throw exceptions.

It's been pointed out that this doesn't forbid throwing moves, which makes it difficult to avoid a leak here:

struct D {
  D() = default;
  D(const D&) noexcept = default;
  D(D&&) { throw 1; }
  void operator()(int* p) const { delete p; }
};

shared_ptr<int> p{new int, D{}};

"The copy constructor" should be changed to reflect that the chosen constructor might not be a copy constructor, and that copies made using any constructor must not throw.

N.B. the same wording is used for the allocator argument, but that's redundant because the Allocator requirements already forbid exceptions when copying or moving.

Proposed resolution:

[Drafting note: the relevant expressions we're concerned about are enumerated in the CopyConstructible and MoveConstructible requirements, so I see no need to repeat them by saying something clunky like "Initialization of an object of type D from an expression of type (possibly const) D shall not throw exceptions", we can just refer to them. An alternative would be to define NothrowCopyConstructible, which includes CopyConstructible but requires that construction and destruction do not throw.]

Change 23.11.3.1 [util.smartptr.shared.const] p8:

D shall be CopyConstructible and such construction shall not throw exceptions. The copy constructor and destructor of D shall not throw exceptions.