Dom*_*rto 11 c++ iterator post-increment
我知道增量/减量运算符的后缀版本通常会由内置类型的编译器优化(即不会进行复制),但这是iterators 的情况吗?
他们本质上只是重载运营商,并且可以在任何数量的方式来实现,但由于他们的行为被严格定义,可以自己进行优化,如果是这样,他们是通过任何/很多编译器?
#include <vector>
void foo(std::vector<int>& v){
for (std::vector<int>::iterator i = v.begin();
i!=v.end();
i++){ //will this get optimised by the compiler?
*i += 20;
}
}
Run Code Online (Sandbox Code Playgroud)
在std::vectorGNU GCC的STL实现(版本4.6.1)的特定情况下,我认为在足够高的优化级别上不会存在性能差异.
前向迭代器的实现vector由提供__gnu_cxx::__normal_iterator<typename _Iterator, typename _Container>.让我们看看它的构造函数和后缀++运算符:
explicit
__normal_iterator(const _Iterator& __i) : _M_current(__i) { }
__normal_iterator
operator++(int)
{ return __normal_iterator(_M_current++); }
Run Code Online (Sandbox Code Playgroud)
其实例化vector:
typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
Run Code Online (Sandbox Code Playgroud)
如您所见,它在内部对普通指针执行后缀增量,然后通过其自己的构造函数传递原始值,从而将其保存到本地成员.通过死值分析消除此代码应该是微不足道的.
但它真的优化了吗?我们来看看.测试代码:
#include <vector>
void test_prefix(std::vector<int>::iterator &it)
{
++it;
}
void test_postfix(std::vector<int>::iterator &it)
{
it++;
}
Run Code Online (Sandbox Code Playgroud)
输出组件(开-Os):
.file "test.cpp"
.text
.globl _Z11test_prefixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE
.type _Z11test_prefixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE, @function
_Z11test_prefixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE:
.LFB442:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 8(%ebp), %eax
addl $4, (%eax)
popl %ebp
.cfi_def_cfa 4, 4
.cfi_restore 5
ret
.cfi_endproc
.LFE442:
.size _Z11test_prefixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE, .-_Z11test_prefixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE
.globl _Z12test_postfixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE
.type _Z12test_postfixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE, @function
_Z12test_postfixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE:
.LFB443:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 8(%ebp), %eax
addl $4, (%eax)
popl %ebp
.cfi_def_cfa 4, 4
.cfi_restore 5
ret
.cfi_endproc
.LFE443:
.size _Z12test_postfixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE, .-_Z12test_postfixRN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE
.ident "GCC: (Debian 4.6.0-10) 4.6.1 20110526 (prerelease)"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
如您所见,在两种情况下都输出完全相同的组件.
当然,对于自定义迭代器或更复杂的数据类型,情况可能不一定如此.但看起来,vector具体来说,前缀和后缀(没有捕获后缀返回值)具有相同的性能.