std::vector c++ size()在成员函数中循环的性能[重复]

goucqfw6  于 12个月前  发布在  其他
关注(0)|答案(4)|浏览(104)

此问题在此处已有答案

Is it good practice to buffer the results of functions before a loop?(6个回答)
Is calling std::vector::size() as fast as reading a variable?(7个回答)
In a "i < vector.size()" loop condition, is size() called each iteration?(10个答案)
15小时前就关门了
类似的问题,但不太具体:Performance issue for vector::size() in a loop
假设我们在一个成员函数中:

void  Object::DoStuff()  {

   for( int k = 0; k < (int)this->m_Array.size(); k++ )
   {  
       this->SomeNotConstFunction();
       this->ConstFunction();

       double x = SomeExternalFunction(i);
   }
}

字符串
1)我愿意相信,如果只调用“SomeExternalFunction”,编译器将优化,而不是冗余地调用m_Array上的size().是这样吗?
2)如果你能把你的速度

int N = m_Array.size()
  for( int k = 0; k < N; k++ ) { ... }


如果你调用的成员函数不是const

编辑不知道这些关于微优化的反对票和讽刺评论来自哪里,也许我可以澄清一下:

首先,这不是优化本身,而是理解编译器会修复什么,不会修复什么。通常我使用size()函数,但我现在问,因为这里数组可能有数百万个数据点。
第二,情况是“SomeNotConstFunction”可能很少有机会改变数组的大小,或者它这样做的能力可能取决于其他变量的切换。所以,我想问的是,编译器在什么时候会失败,当数组真的 * 可能 * 改变时,size()到底花费了多少时间,尽管人类已知的原因是它不会改变?
第三,循环中的操作非常微不足道,只有数百万个,但它们是并行的。我希望通过外部放置值可以让编译器将一些工作向量化。

juzqafwq

juzqafwq1#

不要养成做那样事情的习惯。
在(2)中进行优化的情况是:

  • 安全的
  • 有着明显的不同
  • 这是你的编译器自己无法解决的

很少,而且远远介于两者之间。
如果只是后两点,我会建议你担心一些不重要的事情。然而,第一点是真实的杀手:你不想养成给自己额外的犯错机会的习惯。加速缓慢的正确代码要比调试快速的错误代码容易得多。
现在,也就是说,我将尝试回答你的问题。函数SomeNotConstFunctionSomeConstFunction的定义(大概)在同一个翻译单元中。所以如果这些函数真的没有修改向量,编译器可以弄清楚,它只会“调用”size一次。
然而,编译器无法访问SomeExternalFunction的定义,因此必须假设每次调用该函数都有可能修改您的向量。该函数在循环中的存在保证了size每次都被“调用”。 但是,我把“called”放在引号里,因为它是一个非常简单的函数,几乎肯定会被内联。而且,这个函数非常便宜--两次内存查找(几乎都保证是缓存命中),一次减法和一次右移,或者甚至是一条专门的指令,可以同时执行这两项任务。 即使SomeExternalFunction什么都不做,每次“调用”size`也很可能只占循环运行时间的一小部分。
编辑:为了回应编辑...

what exactly is the time cost incurred by size() when the array really might change

字符串
当你对两个不同版本的代码计时时,你看到的时间差异。如果你做的是非常低级的优化,你不能通过“纯粹的理由”得到答案--你必须经验地测试结果。
如果你真的在做这种低级优化(你可以保证向量不会调整大小),你可能更担心编译器不知道数组的基指针是常量,而不是不知道大小是常量。
如果SomeExternalFunction确实在编译单元的外部,那么无论你做什么,编译器都不可能对循环进行向量化。(我想在链接时可能是这样的.)而且它也不太可能是“平凡的”,因为它需要函数调用开销--至少如果“平凡的”对你和我意味着同样的事情。(同样,我不知道链接时间优化有多好...)
如果您确实可以保证某些操作不会调整向量的大小,那么您可以考虑改进类的API(或者至少是protectedprivate部分),以包含不言而喻不会调整向量大小的函数。

laik7k3q

laik7k3q2#

size方法通常会被编译器内联,所以会有最小的性能影响,尽管通常会有一些。
另一方面,这通常只适用于vector。例如,如果您使用std::list,则size方法可能非常昂贵。
如果你关心性能,你应该习惯使用迭代器和/或像std::for_each这样的算法,而不是基于大小的for循环。

p4tfgftt

p4tfgftt3#

微优化的备注可能是因为vector::size()的两个最常见的实现是

return _Size;

字符串

return _End - _Begin;


将它们从循环中移除可能不会显著提高性能。
如果每个人都知道可以这样做,编译器也可能会注意到。使用现代编译器,如果SomeExternalFunction是静态链接的,编译器**通常能够看到调用是否会影响向量的大小。
相信你的编译器!

5ktev3wc

5ktev3wc4#

在MSVC 2015中,它执行return (this->_Mylast() - this->_Myfirst())。我不能马上告诉你优化器如何处理这个问题;但是除非你的数组是const,否则优化器必须允许你修改它的元素数量的可能性,这使得它很难优化出来。在Qt中,它等同于一个执行return d->size;的内联函数;也就是说,对于QVector。
我在一个特定的项目中已经开始这样做了,但它是针对面向性能的代码。除非你有兴趣深入优化某些东西,否则我不会打扰。它可能是相当快的任何这些方式。在Qt中,它最多是一个指针解引用,并且更多的是类型。看起来它可以在MSVC中有所不同。
我想到目前为止还没有人给出一个明确的答案;但是如果你真的想测试它,让编译器发出汇编源代码,并以两种方式检查它。我不会惊讶地发现高度优化时没有区别。但是不要忘记,调试期间未优化的性能也是一个可能考虑的因素,当涉及到大量的数字运算时。
我认为OP的原始?真的可以用来给予数组是如何声明的。

相关问题