19

移动赋值运算符通常应声明为 noexcept(即,将类型存储在 STL 容器中)。但是复制和交换习惯用法允许在单个代码中定义复制和移动赋值运算符。在这种情况下如何处理 noexcept 说明符?复制构造可以抛出,但我怀疑它是否会违反 noexcept 说明符。

// Is it correct considering that T copy constructor can throw?
T& operator=(T other) noexcept;
4

2 回答 2

13

由于副本是调用进行的,因此它不是您的函数所做的一部分。因此它不能由您的功能控制,因此您不能在noexcept规范中包含此信息。

您唯一能做的就是稳妥行事,并将这两个选项都添加到您的noexcept规范中。当然,这意味着你得到了一些假阴性。

于 2013-09-17T11:19:26.120 回答
10

像往常一样,丹尼尔弗雷正确的。我想要的只是展示一段代码来说明这一点。

#include <iostream>

struct foo {

    foo() = default;

    foo(const foo&) {
        std::cout << "throw\n";
        throw 1;
    }

    foo& operator =(foo) noexcept {
        return *this;
    }
};

int main() {

    foo f, g;
    try {
        f = g; // throws
    }
    catch(int) {
        std::cout << "catch\n";
    }
}

当使用 gcc 4.8.1 ( ) 编译时,-std=c++11 -Wall -Wextra -pedantic它不会给出警告。运行代码会产生以下输出:

throw
catch

因此,复制构造函数在调用时确实会抛出,但内部没有考虑到这一点operator =(),因此,noexcept承诺已经实现。否则,将在catch打印输出之前调用终止。

于 2013-09-17T15:06:08.310 回答