我应该优化还是让编译器这样做?

The*_* do 25 c++ optimization performance

根据效率编写循环的首选方法是什么:方式a)

   /*here I'm hoping that compiler will optimize this  
 code and won't be calling size every time it iterates through this loop*/
    for (unsigned i = firstString.size(); i < anotherString.size(), ++i)
    {
    //do something
    }
Run Code Online (Sandbox Code Playgroud)

或者我应该这样做:方式b)

unsigned first = firstString.size();
unsigned second = anotherString.size();
Run Code Online (Sandbox Code Playgroud)

现在我可以写:

    for (unsigned i = first; i < second, ++i)
    {
    //do something
    }
Run Code Online (Sandbox Code Playgroud)

第二种方式在我看来更糟糕的选择有两个原因:范围污染和冗长,但它的优点是确保每个对象都会调用一次size().
期待您的回答.

kni*_*ttl 62

我通常把这段代码写成:

/* i and size are local to the loop */
for (size_t i = firstString.size(), size = anotherString.size(); i < size; ++i) {
  //do something
}
Run Code Online (Sandbox Code Playgroud)

这样我就不会污染父作用域并避免调用anotherString.size()每个循环迭代.

这对迭代器特别有用:

for(some_generic_type<T>::forward_iterator it = collection.begin(), end = collection.end();
    it != end; ++it) {
   // do something with *it
}
Run Code Online (Sandbox Code Playgroud)

  • 现在踢我自己从来没有想过在11年内这样做! (18认同)
  • 在每次迭代中调用anotherString.size()并不是一个大问题.大小只是对字符串的(可能是内联的)成员访问.在循环中使用类似strlen的东西当然是个问题,因为它必须在每个循环上迭代整个字符串. (6认同)

Ter*_*fey 17

通常,让编译器执行此操作.专注于您正在做的事情的算法复杂性而不是微优化.

但请注意,您的两个示例在语义上不相同 - 如果循环体改变第二个字符串的大小,则两个循环将不会迭代相同的次数.因此,编译器可能无法执行您正在讨论的特定优化.

  • +1用于指出代码的两个代码段不执行相同的操作. (7认同)

In *_*ico 15

我会先使用第一个版本,因为它看起来更干净,更容易打字.然后,您可以对其进行分析,以查看是否需要进行更多优化.

但我非常怀疑第一个版本会导致显着的性能下降.如果容器实现size()如下:

inline size_t size() const
{
    return _internal_data_member_representing_size;
}
Run Code Online (Sandbox Code Playgroud)

然后编译器应该能够内联函数,省略函数调用.我的编译器对标准容器的实现都是这样做的.


Joh*_*lph 7

优秀的编译器如何优化您的代码?完全没有,因为它不能确定是否size()有任何副作用.如果size()您的代码依赖于任何副作用,那么在可能的编译器优化之后它们现在就消失了.

从编译器的角度来看,这种优化实际上并不安全,您需要自己完成.自己动手并不意味着你需要引入另外两个局部变量.根据您的大小实现,它可能是O(1)操作.如果size也是内联声明的,那么你也可以省去函数调用,使调用与size()本地成员访问一样好.

  • @Johannes:你听起来很难让'size()`成为O(1).`std :: string :: size()`是O(1). (6认同)
  • 考虑到大小是一个`const`函数,编译器可以知道它对字符串没有副作用... (4认同)
  • 即使使用可变字符串,使size()成为O(1)操作也很容易. (3认同)
  • 嗯......我很确定编译器_can_在_some_情况下,确定调用大小没有副作用... (3认同)
  • @JohannesRudolph:我呢?只是通过每次破坏性操作更新长度有什么问题?例如,当附加大小为n的字符串时,`length + = n`.是否存在在执行操作时无法在O(1)时间内轻松更新长度的操作?(是的,这是无关紧要的,只是问). (2认同)

Bre*_*ias 6

不要预先优化您的代码.如果遇到性能问题,请使用分析器查找,否则会浪费开发时间.只需编写最简单/最干净的代码即可.