c++ 调用std::vector::size()和阅读变量一样快吗?

cnwbcb6i  于 9个月前  发布在  其他
关注(0)|答案(7)|浏览(97)

我做了一个大的整数向量的广泛的计算.向量的大小在计算过程中不会改变.向量的大小是经常访问的代码.什么是更快的一般:

  • 使用vector::size()函数或
  • 使用辅助常量vectorSize来存储向量的大小?

我知道编译器通常在设置正确的编译器标志时内联size()函数,但是,这并不能保证。

ar5n3qh5

ar5n3qh51#

有意思的问题。
那么,接下来会发生什么呢?如果你用gdb调试,你会看到类似3个成员变量的内容(名称不准确):

  • _M_begin:指向动态数组第一个元素的指针
  • _M_end:指针一通过动态数组的最后一个元素
  • _M_capacity:指针一,指针指向可存储在动态数组中的最后一个元素

因此,vector<T,Alloc>::size()的实现通常被简化为:

return _M_end - _M_begin;  // Note: _Mylast - _Myfirst in VC 2008

字符串
现在,在考虑可能的实际优化时,有两件事需要考虑:

  • 这个函数会被内联吗?可能:我不是编译器的作者,但这是一个很好的选择,因为函数调用的开销会使这里的实际时间相形见绌,而且因为它是模板化的,所以我们在翻译单元中有所有可用的代码
  • 结果会被缓存吗(比如有一个未命名的局部变量):很有可能,但是除非你反汇编生成的代码,否则你不会知道

换句话说:

  • 如果您自己存储size,则很有可能它的速度会与编译器获取它的速度一样快。
  • 如果不这样做,则取决于编译器是否能够确定没有其他东西正在修改vector;如果不能,则无法缓存该变量,并且每次都需要执行内存读取(L1)。

这是一个微优化。一般来说,它不会引起注意,因为性能无关紧要,或者编译器会执行它。在编译器不应用优化的关键循环中,它可以是一个显著的改进。

kuarbcqp

kuarbcqp2#

根据我对1998年C++规范的理解,vector<T>::size()需要常数时间,而不是线性时间。因此,这个问题可能归结为读取局部变量是否比调用一个工作量很小的函数更快。
因此,我认为将向量的size()存储在一个局部变量中会使程序的速度提高一点,因为你只会调用这个函数一次(因此执行所需的时间很小),而不是多次。

628mspwn

628mspwn3#

vector::size()的性能:是否与阅读变量一样快?
大概不会吧。
有关系吗
大概不会吧。
除非每次迭代所做的工作很小(如一个或两个整数运算),否则开销将微不足道。

7z5jn7bk

7z5jn7bk4#

在我见过的每个实现中,看到vector::size()执行end()begin()的减法,即它不如阅读变量快。
当实现一个向量时,实现者必须在哪一个最快之间做出选择,end()size(),即存储初始化元素的数量或指向最后一个初始化元素之后的元素的指针/迭代器。换句话说,通过使用迭代器进行迭代。
如果你担心size()的性能,可以像这样编写基于索引的for循环;

for (size_t i = 0, i_end = container.size(); i < i_end; ++i){
// do something performance critical
}

字符串

64jmpszr

64jmpszr5#

我总是保存vector.size()在一个局部变量中(如果大小在循环中没有改变!)。
在每次迭代中调用它比保存在局部变量中要快,至少我是这样经历的。
我不能给给予你任何真实的数字,因为我很久以前就测试过这个了,但是从我的记忆中,它产生了明显的差异(但是可能只在调试模式下),特别是在嵌套循环的时候。
对于所有抱怨微优化的人:
这是一个单一的额外的代码行,没有引入任何缺点。

5t7ly7z5

5t7ly7z56#

你可以为你的循环体写一个functor,然后通过std::for_each调用它。它会为你执行迭代,然后你的问题就没有意义了。然而,你为每个循环迭代引入了一个函数调用(可能会也可能不会内联),所以如果你没有得到你期望的性能,你最好对它进行分析。

xcitsw88

xcitsw887#

在考虑这种微优化之前,一定要先了解应用程序的配置文件。记住,即使它执行减法,编译器仍然可以轻松地以多种方式优化它,从而消除任何性能损失。

相关问题