【发布时间】:2015-09-27 19:37:27
【问题描述】:
gcc,clang 和 VS2015 在抛出对象a 之后,不会在下面的代码中省略对移动构造函数的调用。在我看来,§8.12[class.copy]/31 (N4140) 的要点 (31.2) 中建立的条件已经满足。
#include <iostream>
struct A
{
A() { std::cout << "Default ctor " << '\n'; }
A(const A& a) { std::cout << "Copy ctor" << '\n'; }
A(A&& a) { std::cout << "Move ctor" << '\n'; }
~A() { std::cout << "Destructor " << '\n'; }
};
int main()
{
try
{
A a;
throw a;
}
catch(A& a) { std::cout << "Caught" << '\n'; }
}
注意a 是一个左值,但根据§12.8/32,重载决议
首先执行为副本选择构造函数,就好像对象是由右值指定的一样。也就是说,调用移动构造函数是可以的。如果你删除上面移动构造函数的定义,复制构造函数会被调用,但同样,它不会被忽略!
我知道标准没有强制要求复制省略,但我很想知道是否有任何特殊条件可以证明上述三个编译器在这个特定示例中避免了这种优化这一事实。
gcc 的示例输出,来自上面的链接:
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
默认演员
移动器
析构函数
抓到
析构函数
【问题讨论】:
-
它走在非凡的道路上,谁在乎呢?等效的happy path 完全优化
-
我认为这是关于如果局部变量的构造有副作用则不能省略的措辞。不确定是否真的存在冲突,但作为简单的规则,它们可能对编译器有效地发生冲突。
-
@Cheersandhth.-Alf:复制省略是明确允许的,这样即使有副作用,编译器也能做到。
-
@DietmarKühl:不,我不是在谈论移动构造函数的副作用。
-
@DietmarKühl VS2015 即使在禁用优化的情况下也总是进行复制省略。我不知道有关 gcc 和 clang 的详细信息。但是您可以在上面提供的链接中验证 gcc 中使用的编译器开关,
标签: c++ exception c++14 copy-elision