在阅读了 cppreference 的复制省略之后我想玩异常(exception)和复制省略。 所以我在 coliru 上用 gcc 7.2 写了下面的代码
#include <iostream>
class Exception
{
public:
Exception() { std::cout << "constructed\n"; }
Exception(Exception& other) {std::cout << "copy constructed\n";}
Exception(const Exception& other) {std::cout << "copy constructed\n";}
Exception(Exception&& other) {std::cout << "move constructed\n";}
};
void foo()
{
throw Exception();
}
int main()
{
try
{
foo();
}
catch(Exception e )
{
}
}
输出
constructed
copy constructed
我们可以看到调用了复制构造函数,即使在使用 -O2 调用 gcc 时也会发生这种情况。 在我看来,根据以下条款,这段代码应该有资格复制省略:
When handling an exception, if the argument of the catch clause is of the same type (ignoring top-level cv-qualification) as the exception object thrown, the copy is omitted and the body of the catch clause accesses the exception object directly, as if caught by reference.
那么为什么要调用拷贝构造函数呢?为什么复制省略在这种情况下不起作用?
最佳答案
cppreference 对此不准确。事实上,除了在常量表达式 (constexpr
) 或常量初始化(静态或线程-本地的)。在您的示例中情况并非如此。
参见 [class.copy.elision]/1在当前的 C++17 草案中(强调我的):
When certain criteria are met, ... elision of copy/move operations, called copy elision, is permitted in the following circumstances:
— in a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object can be omitted by constructing the automatic object directly into the exception object
Copy elision is required where an expression is evaluated in a context requiring a constant expression and in constant initialization.
这意味着有一天它可能会作为编译器优化来实现,但目前并非如此。
因此,暂时用 const&
来 catch
是明智的(也可以避免意外切片)。
关于c++ - 复制省略和异常(exception),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48259160/