2802. shared_ptr constructor requirements for a deleter

Section: 20.3.2.2.2 [util.smartptr.shared.const] Status: C++17 Submitter: United States Opened: 2016-11-09 Last modified: 2020-09-06

Priority: 2

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

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

View all issues with C++17 status.

Discussion:

Addresses US 127

It should suffice for the deleter D to be nothrow move-constructible. However, to avoid potentially leaking the pointer p if D is also copy-constructible when copying the argument by-value, we should continue to require the copy constructor does not throw if D is CopyConstructible.

Proposed change:

Relax the requirement the D be CopyConstructible to simply require that D be MoveConstructible. Clarify the requirement that construction of any of the arguments passed by-value shall not throw exceptions. Note that we have library-wide wording in clause 17 that says any type supported by the library, not just this delete, shall not throw exceptions from its destructor, so that wording could be editorially removed. Similarly, the requirements that A shall be an allocator satisfy that neither constructor nor destructor for A can throw.

[2016-12-16, Issues Telecon]

Priority 3; Jonathan to provide wording.

[2017-02-23, Jonathan comments and suggests wording]

I don't think the Clause 17 wording in [res.on.functions] is sufficient to require that the delete expression is well-formed. A class-specific deallocation function ([class.free]) would not be covered by [res.on.functions] and so could throw:

struct Y { void operator delete(void*) noexcept(false) { throw 1; } };

[Kona 2017-02-27]

Accepted as Immediate to resolve NB comment.

Proposed resolution:

This wording is relative to N4640.

  1. Modify 20.3.2.2.2 [util.smartptr.shared.const] as indicated:

    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);
    

    -8- Requires: D shall be CopyMoveConstructible and such construction of d and a deleter of type D initialized with std::move(d) shall not throw exceptions. The destructor of D shall not throw exceptions. The expression d(p) shall be well formed, shall have well -defined behavior, and shall not throw exceptions. A shall be an allocator (17.5.3.5). The copy constructor and destructor of A shall not throw exceptions. When T is […].