编译器优化或我的误解

Compiler optimization or my misunderstanding

本文关键字:误解 我的 优化 编译器      更新时间:2023-10-16

最近我在测试一些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()

谢谢:)