自动循环和优化

时间:2013-06-12 11:46:02

标签: c++ loops optimization c++11 auto

你能解释一下为什么计算时间与以下代码存在差异(未优化)。我怀疑RVO与移动建设有关,但我并不确定。

一般来说,遇到此类案件时的最佳做法是什么?在初始化非POD数据时,循环中的自动声明被认为是一种不好的做法吗?

在循环中使用自动:

std::vector<int> foo()
{
    return {1,2,3,4,5};
}

int main()
{
    for (size_t i = 0; i < 1000000; ++i)
        auto f = foo();
    return 0; 
}

输出

  

./ a.out 0.17s用户0.00s系统97%cpu 0.177总计

循环外的矢量实例:

std::vector<int> foo()
{
    return {1,2,3,4,5};
}

int main()
{
    std::vector<int> f;

    for (size_t i = 0; i < 1000000; ++i)
         f = foo();
    return 0;
}

输出

  

./ a.out 0.32s用户0.00s系统99%cpu 0.325总计

2 个答案:

答案 0 :(得分:2)

  

我怀疑RVO对移动构造,但我不太确定。

是的,这几乎肯定是正在发生的事情。第一种情况是从函数的返回值初始化变量:在这种情况下,可以通过使函数初始化它来省略移动。第二种情况是从返回值中移出 - 分配;作业不能被省略。我相信GCC即使在优化级别为零也会执行省略,除非您明确禁用它。

在最后一种情况下(-O3,现已从问题中删除),编译器可能会注意到循环没有副作用,并将其完全删除。

通过声明向量volatile并使用优化进行编译,您可能(或可能不)获得更有用的基准。这将迫使编译器在每次迭代时实际创建/分配它,即使它认为它更清楚。

  

在初始化非POD数据时,循环中的自动声明被视为不良做法吗?

没有;如果有的话,在最狭窄的范围内声明事物被认为是更好的做法。因此,如果仅在循环中需要它,则在循环中声明它。在某些情况下,通过在循环外声明一个复杂的对象来避免在每次迭代中重新创建它,可以获得更好的性能。但只有在你确定性能优势(a)存在且(b)值得失去地方时才这样做。

答案 1 :(得分:1)

我没有看到您的示例与auto有任何关系。你写了两个不同的程序。

虽然

for (size_t i = 0; i < 1000000; ++i)
    auto f = foo();

相当于

for (size_t i = 0; i < 1000000; ++i)
    std::vector<int> f = foo();

- 这意味着,您创建一个新的向量(并销毁旧向量)。是的,在你的foo - 使用RVO的实现中,但这不是重点:你仍然在外部循环为vector腾出空间的地方创建一个新的f

摘录

std::vector<int> f;
for (size_t i = 0; i < 1000000; ++i)
     f = foo();

分配用于现有的向量。并且,是的,对于RVO,它可能会变成 move-assign ,具体取决于foo,并且它适用于您的情况,因此您可以预期它会很快。但它仍然 是另一回事 - 它始终是负责管理资源的f

但是你在这里表现得很漂亮的是遵循一般规则通常是有意义的

  

声明变量尽可能接近其使用。

请参阅this Discussion