隐式移动构造函数应为否,除非可能

Implicit move constructor shall be noexcept if possible

本文关键字:移动 构造函数      更新时间:2023-10-16

基本上按照标准:

继承构造函数 (12.9( 和隐式声明的特殊成员函数(子句 12(具有异常规范。如果f是继承构造函数或隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符或移动赋值运算符,则其隐式异常规范指定类型 IDT当且仅当异常规范允许Tf的隐式定义直接调用的函数; 如果f直接调用的任何函数允许所有异常,则允许所有异常,并且f具有异常规范noexcept(true)如果它直接调用的每个函数都不允许异常。

因此,截取的以下代码应具有隐式noexcept移动构造函数:

template<typename _Tp>
class Foo
{
public:
Foo() = default;
explicit Foo(const std::string& s, const std::function<bool(_Tp&)>& f) : stringField(s), funcField(f) {}
private:
const std::string stringField;
std::function<bool(_Tp&)> funcField;
};

但不幸的是,它没有:

int main()
{
std::cout << "std::string: " << std::is_nothrow_move_constructible_v<std::string> << std::endl;
std::cout << "std::function: " << std::is_nothrow_move_constructible_v<std::function<bool(std::string&)>> << std::endl;
std::cout << "string_t: " << std::is_nothrow_move_constructible_v<Foo<std::string>> << std::endl;
return 0;
}

指纹

std::string: 1  
std::function: 1  
string_t: 0

在 Ubuntu 18.04 LTS 上使用 g++ 8.3.0

我错过了什么吗?

我缺少什么吗?

是的。const

成员Foo::stringField不是std::string,而是const std::stringconst std::string不是 nothrow move 可构造函数1,因此Foo的隐式移动构造函数也不是。

1Const 右值无法绑定到非常量右值引用,因此不会使用移动构造函数。相反,使用复制构造函数,并且可能会抛出std::string的复制构造函数。