unique_ptr<T,Deleter> 构造函数要求 Deleter 不抛出

e27*_*314 2 c++ language-lawyer noexcept c++17

unique_ptr(构造函数)@cppreference

unique_ptr( pointer p, /* see below */ d1 ) noexcept;
(3) 
unique_ptr( pointer p, /* see below */ d2 ) noexcept;
(4)
Run Code Online (Sandbox Code Playgroud)

这里有 2 个构造函数,Deleter 案例的描述是非参考的

a) If D is non-reference type A, then the signatures are:
unique_ptr(pointer p, const A& d) noexcept;
(1) (requires that Deleter is nothrow-CopyConstructible)
unique_ptr(pointer p, A&& d) noexcept;
(2) (requires that Deleter is nothrow-MoveConstructible)
Run Code Online (Sandbox Code Playgroud)

我检查了 gcc 和 llvm 代码,但我没有看到nothrow强制要求。构造函数 3-4 被标记,noexcept因此Deleter在调用其构造函数时不应抛出是有道理的。但我不确定为什么在他们提供的示例中,构造函数没有标记为noexcept.

struct D { // deleter
    D() {};
    D(const D&) { std::cout << "D copy ctor\n"; }
    D(D&) { std::cout << "D non-const copy ctor\n";}
    D(D&&) { std::cout << "D move ctor \n"; }
    void operator()(Foo* p) const {
        std::cout << "D is deleting a Foo\n";
        delete p;
    };
};
Run Code Online (Sandbox Code Playgroud)

Mar*_*low 8

我检查了 gcc 和 llvm 代码,但我没有看到nothrow强制要求。

它没有强制执行 - 直接执行。
这是标准中实际文字

对于第一个构造函数,如果D不是引用类型,D则应满足Cpp17CopyConstructible要求,并且该构造不应通过异常退出。对于第二个构造函数,如果D不是引用类型,D则应满足Cpp17MoveConstructible要求,并且该构造不应通过异常退出。

这就是说,如果您的复制/移动构造函数通过异常退出,则您有未定义的行为。[ 在这种情况下,'shall' 是对用户的要求。]

如果你很幸运,那么程序会terminate用一条好消息来调用。但是,您没有任何保证。

(稍后)注意:要求不是它们是noexcept,而是它们不通过异常退出。这就是为什么 cppreference 上的例子很好。