我创建了一个实例化类10亿次的循环,并且非常惊讶地看到它在0ms内运行并且根据Windows任务管理器没有消耗CPU时间。
正如您从下面的代码中看到的那样,我显然没有对默认构造函数做任何事情,但我假设会有一个重要的CPU命中,然后一遍又一遍地破坏该类。有人可以解释为什么没有明显的CPU命中?
class Cmytest {
public:
int lookup();
bool create_rec();
bool delete_rec();
};
void test() {
for (int i=0; i<1000000000; i++) {
Cmytest mytest;
}
}
int main()
{
test();
return 0;
}
在运行上面的测试之后,我想看看如果我在两个不同的线程中运行test()将会发生什么(20亿次迭代,但不包括代码以保持简洁性)并且没有明显的差异。
请指教,谢谢!
更新:
问这个的原因是因为我经常使用构图,而且我有一个Cmytest成员的类。根据某些数据条件,Cmytest的成员将被执行,而在其他情况下,它什么都不做。这是一个长期运行的Web应用程序,我一直关注效率。
最终更新:
我决定让实例做一些事情(以确保它不仅仅是优化而忽略了什么都不做的循环)。我在这里看到了以下成员:
Cmytest::void count(int& i) {
i++;
}
然后我在循环中调用它:
int iter=0;
void test() {
for (int i=0; i<1000000000; i++) {
Cmytest mytest;
mytest.count(iter);
}
}
结果是10亿,如果在两个线程中运行,那么20亿是正确的。通过这个,我只能推断工作正在进行,对象正在被重用,这解释了我观察到的效率。
答案 0 :(得分:12)
在&#34; as-if规则&#34;下,编译器可以以任何方式转换您的程序,使得可观察的副作用保持不变†。除了返回0
之外,您的程序没有任何可观察到的副作用,因此几乎整个程序都可以解析为空。
即使我们忽略了这一点,当一个对象在循环中声明时,编译器通常会反复重复使用同一个对象,而不必重新分配内存(但需要重新初始化对象)。在这个例子中,编译器甚至可以看到对象保持不变,可以重用,而不必重新初始化它。无论如何,你的班级无论如何都没有初始化的状态。
为了演示,如果我在Clang中使用最大优化编译代码,test
函数的结果程序集如下:
_Z4testv:
.cfi_startproc
ret
它立即返回。
†复制elision是一种明确允许的优化,即使它确实修改了程序的可观察副作用。
答案 1 :(得分:2)
根据编译器和传递给它的标志,它可能决定优化不起作用的代码。在这种情况下,您声明一个从未使用过的变量,因此编译器决定优化此代码是安全的,因此它永远不会被执行。