首页 > 解决方案 > 如果可能,隐式移动构造函数应为 noexcept

问题描述

基本上按照标准:

继承构造函数 (12.9) 和隐式声明的特殊成员函数 (Clause 12) 具有异常规范。Iff是继承构造函数或隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符或移动赋值运算符,其隐式异常规范指定类型 IDT当且仅当异常规范T允许 由的隐式定义直接调用的函数;如果它直接调用的任何函数允许所有异常,并且具有异常规范,则允许所有异常fff 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

有什么我想念的吗?

标签: c++move-constructornoexcept

解决方案


有什么我想念的吗?

是的。const

成员Foo::stringField不是std::string,它是const std::stringconst std::stringis not nothrow move constructible 1,因此隐式 move 构造函数Foo既不是。

1 const rvalue 不能绑定到非 const rvalue 引用,所以不会使用 move 构造函数。相反,使用了复制构造函数,std::string并且可能会抛出复制构造函数。


推荐阅读