编译器优化或我的误解
Compiler optimization or my misunderstanding
最近我在测试一些C++的深角和暗角,我对一个微妙的点感到困惑。事实上,我的测试很简单:
// problem 1
// no any constructor call, g++ acts as a function declaration to the (howmany())
// g++ turns (howmany()) into (howmany(*)())
howmany t(howmany());
// problem 2
// only one constructor call
howmany t = howmany();
我的期望是:;第一个howmany()
构造函数调用将生成一个临时对象,然后编译器将使用该临时对象和复制构造函数来实例化t。然而,编译器的输出确实让我感到困惑,因为输出只显示了一个构造函数调用。我的朋友提到了编译器传递值优化,但我们不确定。我想知道这里会发生什么?
问题2的输出如下。问题1完全超出了对象实例化的范围,因为编译器将其行为为函数指针声明。
howmany()
~howmany()
我的测试课程是:
class howmany {
public:
howmany() {
out << "howmany()" << endl;
}
howmany(int i) {
out << "howmany(i)" << endl;
}
howmany(const howmany& refhm) {
out << "howmany(howmany&)" << endl;
}
howmany& operator=(const howmany& refhm) {
out << "operator=" << endl;
}
~howmany() {
out << "~howmany()" << endl;
}
void print1() {
cout << "print1()" << endl;
}
void print2() {
cout << "print2()" << endl;
}
};
这是这里最麻烦的解析:
howmany t( howmany() );
为了解决这个问题,你需要添加一组额外的parens:
howmany t( (howmany()) );
^ ^
clang
在这里非常有用,并警告您:
warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
howmany t( howmany() );
^~~~~~~~~~~~~
main.cpp:31:12: note: add a pair of parentheses to declare a variable
howmany t( howmany() );
^
( )
解决此问题的另一种方法是使用C++11统一初始化语法:
howmany t{ howmany{} };
^ ^^ ^
更新
为了解决您添加到问题中的2
部分,在某些情况下,标准草案允许省略复制/移动结构。我们可以从12.8
复制和移动类对象第31段中看到这一点,其中写道:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标视为引用同一对象的两种不同方式,而该对象的销毁发生在两个对象在没有优化的情况下被销毁的较晚时间。122这种复制/移动操作的省略称为复制省略,在以下情况下允许
并包括以下项目符号:
当尚未绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv不合格类型的类对象时,可以通过将临时对象直接构建到省略的复制/移动的目标中来省略复制/移动操作
是的,这是编译器可以做的优化之一。即使复制构造函数有副作用,编译器也可以消除临时对象创建!
从上面的答案中得到线索后,我发现了真正的问题。在我的情况下,特别是问题2,编译器消除了复制构造过程,因为howmany()构造函数调用的返回值与多少t对象完全相同,因此编译器只是消除了复制构建过程,以便进行优化。这个问题的更多细节在维基百科上有介绍,请看那里。返回值优化
-fno-elide构造函数是g++标志之一,负责禁用优化。在cmake中,我们只需要设置它。
set(CMAKE_CXX_FLAGS "-fno-elide-constructors")
在禁用优化之后,程序的输出变成了我所期望的。
howmany()
howmany(howmany&)
~howmany()
~howmany()
谢谢:)
- 我的神经网络不起作用 [XOR 问题]
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 我的字符计数代码计算错误.为什么
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- cmake在我的项目中所需的所有静态库都不成功
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 为什么我的for循环不能正确获取argv
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 0-1背包代码中的错误.我的代码中有什么错误
- 当我的阵列太大时出现分段错误
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 为什么二进制搜索在我的测试中不起作用
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- 我的代码中有错误吗?使用BGI图形的C++代码对我不起作用
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- OpenGL在启用深度测试时不会丢弃我的碎片
- 为什么我的 std::ref 无法按预期工作?
- clang整洁10忽略了我的NOLINT命令
- 编译器优化或我的误解