C++:将构造函数调用到临时对象

kam*_*iro 4 c++ optimization

假设我有以下内容:

int main() {
    SomeClass();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果没有优化,将调用SomeClass()构造函数,然后调用它的析构函数,并且对象将不再存在.

但是,根据IRC通道,如果编译器认为对SomeClass构造函数/析构函数没有副作用,那么构造函数/析构函数调用可能会被优化掉.

我认为明显的方法是不使用一些构造函数/析构函数(例如使用函数或静态方法等),但有没有办法确保调用构造函数/析构函数?

seh*_*ehe 7

但是,根据IRC通道,如果编译器认为对SomeClass构造函数/析构函数没有副作用,那么构造函数/析构函数调用可能会被优化掉.

粗体部分是错误的.这应该是:知道没有观察到的行为

例如,从最新标准的第1.9节(有更多相关报价):

执行格式良好的程序的一致实现应该产生与具有相同程序和相同输入的抽象机的相应实例的可能执行之一相同的可观察行为.但是,如果任何此类执行包含未定义的操作,则此国际标准不要求使用该输入执行该程序的实现(甚至不考虑第一个未定义操作之前的操作).

事实上,这整个机制支撑着最普遍存在的C++语言习惯:资源获取是初始化

背景资料

让编译器优化掉平凡的case-constructors是非常有帮助的.它允许迭代器编译为与使用原始指针/索引器完全相同的性能代码.

它也允许函数对象编译为与内联函数体完全相同的代码.

这使得C++ 11 lambdas 非常适合简单的用例:

factorial = std::accumulate(begin, end, [] (int a,int b) { return a*b; });
Run Code Online (Sandbox Code Playgroud)

lambda编译成类似于的仿函数对象

struct lambda_1
{
     int operator()(int a, int b) const 
     { return a*b; }
};
Run Code Online (Sandbox Code Playgroud)

编译器看到构造函数/析构函数可以被省略并且函数体被内联.最终结果是最佳的1


更多(不)可观察的行为

该标准包含一个非常有趣的例子,相反,激发你的想象力.

§20.7.2.2.3

[ Note:由临时对象构造和销毁引起的使用计数更新不是可观察到的副作用,因此实现可以通过不同的方式满足效果(和隐含的保证),而不创建临时的.特别是在示例中:

shared_ptr<int> p(new int);
shared_ptr<void> q(p);
p = p;
q = p;
Run Code Online (Sandbox Code Playgroud)

两项任务都可以是无操作. —end note ]

IOW:不要低估优化编译器的能力.这绝不意味着语言保证会被抛到窗外!

1虽然可以有更快的算法来获得因子,取决于问题域:)