我正在考虑编写不可复制的异常类。我觉得这很有趣,因为那样我就不必担心在复制构造函数中分配期间可能抛出的异常。如果异常对象的创建成功,则一切正常并且 std::terminate
应该没有问题。
struct exception
{
exception() = default;
exception(const exception&) = delete;
exception(exception&&) noexcept = default;
~exception() noexcept = default;
auto operator=(const exception&) -> exception& = delete;
auto operator=(exception&&) noexcept -> exception& = delete;
};
int main()
{
try {
try {
throw exception{};
} catch (...) {
std::rethrow_exception(
std::current_exception());
}
} catch (const exception& e) {
return 1;
}
}
GCC-4.7 和 Clang-3.2 接受以上代码。然而,我有点惊讶。据我所知,有几种情况可能会复制异常对象,例如std::current_exception()
和 std::rethrow_exception()
。
问题:根据 C++11,上面的代码是否正确,即是否会被所有符合 C++11 的编译器接受?
已编辑:向示例中添加了 std::rethrow_exception
和 std::current_exception
。两个编译器都接受这个版本。这应该清楚地表明,如果编译器在抛出异常时不需要复制构造函数,那么在使用这两个函数时编译器将不需要复制构造函数。
最佳答案
current_exception
表示它指的是当前异常或它的拷贝,但没有说明是哪个。这向我表明:
- 未指定是否被复制[*]
- 因此,您的异常类不是很好(如果有人可能对其调用
current_exception
肯定不是) - 因此,它在某些实现中起作用也就不足为奇了。可能不会规定当前异常不能被复制,除非实现者有要求或希望实现者避免复制。
只需抛出东西并通过引用捕捉它就可以了。 throw
表达式中的 temporary 是“用于初始化”实现所使用的对象以保留当前异常,因此它可以被移动或复制(根据类支持),并且移动/copy 可以省略。
就其值(value)而言,make_exception_ptr
被指定为始终 复制。您可能会争辩说这是一个缺陷:e
可以是按值参数,在这种情况下移动可能会更好。但这是我的浮躁和无知的印象,我以前从未见过这些功能。
[*] current_exception
是否“每次调用时创建一个新拷贝”是明确未指定的,但我不完全确定这是否意在暗示未指定它是否创建第一次调用时的新拷贝。
关于c++ - 可移动但不可复制的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12824176/