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

Mot*_*tti 5 c++ exception move-semantics

C++ 中关于异常的最佳实践似乎是按值抛出,按引用捕获。我看了看<exception>cppreference,我看到它std::exception有一个复制构造函数但没有移动构造函数,这是为什么?难道没有移动构造函数可以廉价地按值捕获从而简化指导​​方针吗?

How*_*ant 2

的后代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>{});
}
Run Code Online (Sandbox Code Playgroud)

类拥有动态分配的消息并具有复制构造函数的唯一方法noexcept是共享该所有权(引用计数)。所以std::runtime_error本质上是一个常量、引用计数的字符串。

根本没有动机为这些类型提供移动构造函数,因为复制构造函数不仅已经非常快,而且程序的异常路径仅在特殊情况下执行。移动构造函数唯一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';
    }
}
Run Code Online (Sandbox Code Playgroud)

输出(对我来说):

std::exception
Run Code Online (Sandbox Code Playgroud)