int main() {
SomeClass();
return 0;
}
如果不进行优化,SomeClass()构造函数将被调用,然后其析构函数将被调用,对象就不存在了。
然而,根据IRC频道的说法,如果编译器认为SomeClass构造函数/析构函数没有副作用,那么该构造函数/析构函数调用可能会被优化掉。
我想,显而易见的方法是不使用某些构造函数/析构函数(例如使用函数、静态方法等),但是否有一种方法可以确保调用构造函数/析构函数呢?
int main() {
SomeClass();
return 0;
}
如果不进行优化,SomeClass()构造函数将被调用,然后其析构函数将被调用,对象就不存在了。
然而,根据IRC频道的说法,如果编译器认为SomeClass构造函数/析构函数没有副作用,那么该构造函数/析构函数调用可能会被优化掉。
我想,显而易见的方法是不使用某些构造函数/析构函数(例如使用函数、静态方法等),但是否有一种方法可以确保调用构造函数/析构函数呢?
事实上,这整个机制是C ++语言中最普遍的习惯用法之一:资源获取即初始化。执行良好形式的程序的符合实现应产生与相应的抽象机器实例在具有相同程序和相同输入的情况下的可能执行之一相同的可观察行为。但是,如果任何这样的执行包含未定义的操作,则本国际标准对执行具有该输入的该程序(甚至是第一个未定义操作之前的操作)不提出要求。
factorial = std::accumulate(begin, end, [] (int a,int b) { return a*b; });
struct lambda_1
{
int operator()(int a, int b) const
{ return a*b; }
};
标准中提供了一个非常有趣的反例,以激发您的想象力。
IOW: 不要低估优化编译器的威力。这绝不意味着语言保证应该被抛弃!虽然根据问题域可能存在更快的算法来获得阶乘 :)§ 20.7.2.2.3
[ Note:
The use count updates caused by the temporary object construction and destruction are not observable side effects, so the implementation may meet the effects (and the implied guarantees) via different means, without creating a temporary. In particular, in the example:
shared_ptr<int> p(new int); shared_ptr<void> q(p); p = p; q = p;
both assignments may be no-ops.
—end note ]
如果编译器优化掉了构造函数/析构函数调用的可见效果,那么它就有缺陷。如果没有可见效果,那么你也不应该注意到它。
然而,让我们假设你的构造函数或析构函数以某种方式具有可见效果(因此对象的构造和后续销毁不是有效的无操作),而编译器可以合理地认为它没有(虽然我想不出这样的情况,但这可能只是我缺乏想象力)。那么以下任何一种策略都应该奏效:
确保编译器看不到构造函数和/或析构函数的定义。如果编译器不知道构造函数/析构函数的作用,它就不能假设它没有效果。但请注意,这也禁用了内联。如果您的编译器不进行跨模块优化,只需将构造函数/析构函数放入不同的文件中即可。
确保您的构造函数/析构函数实际上具有可观察行为,例如通过使用易失变量(在C++中,每个易失变量的读取或写入都被视为可观察行为)。
然而,让我再次强调,除非您的编译器极其有缺陷(在这种情况下,我强烈建议您更换编译器 :-)),否则您很可能不需要做任何事情。