为什么std::exception没有移动构造函数?

6

关于C ++中异常的最佳实践似乎是 抛出值,引用捕获。我查看了<exception>cppreference,发现std::exception有一个拷贝构造函数但没有移动构造函数,这是为什么呢?拥有移动构造函数难道不会允许捕获值并因此简化指南吗?


12
由于按值捕获将导致切片,并使异常类型层次结构变得无意义,因此我认为准则不会改变。 - StoryTeller - Unslander Monica
2个回答

2
< p > std::exception 的后代拥有数据。例如,std::runtime_error 拥有其 what() 消息。该消息是动态分配的,因为它可以是任意长度的消息。

然而,复制构造函数被标记为 noexcept(隐式),因为 std::exception 的复制构造函数是 noexcept 的。

#include <stdexcept>
#include <type_traits>

int
main()
{
    static_assert(std::is_nothrow_copy_constructible<std::runtime_error>{});
}

唯一让类拥有动态分配消息并具有noexcept复制构造函数的方法是共享所有权(引用计数)。因此,std :: runtime_error本质上是一个const、引用计数的字符串。
没有必要为这些类型提供移动构造函数,因为复制构造函数不仅已经非常快,而且程序的异常路径只在异常情况下执行。std :: runtime_error的移动构造函数唯一能做的事情就是消除原子增量/减量,但是没有人关心。
你已经可以通过值便宜地捕获。但是该指南存在的原因是异常通常是继承层次结构的一部分,并且按值捕获将切片异常:
#include <exception>
#include <iostream>
#include <stdexcept>

int
main()
{
    try
    {
        throw std::runtime_error("my message");
    }
    catch (std::exception e)
    {
        std::cout << e.what() << '\n';
    }
}

输出结果(对我来说):

std::exception

1

我检查了几个编译器,显然try/catch机制不使用移动语义。

#include <iostream>
using namespace std;

struct err {
    err() { cout << "created err" << endl; }
    err(const err&) { cout << "copied err" << endl; } // Compilation error if this is commented out
    err(err&&) noexcept { cout << "moved err" << endl; }
    ~err() { cout << "destroyed err" << endl; }
};

void foo() {
    throw err{};
}

int main() {
    try {
        cout << "calling foo" << endl;
        foo();
        cout << "called foo" << endl;
    }
    catch (err e) {
        cout << "caught err" << endl;
    }
}

输出:

调用foo
创建错误
复制错误
捕获错误
销毁错误
销毁错误

因此,拥有移动构造函数是无意义的。

为什么会这样可能是另一个问题的事情 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接