C++ 后缀的低效性++;/--如何优化STL迭代器的运算符?
我知道编译器通常会针对内置类型优化增量/减量运算符的后缀版本(即,不会进行复制),但对于C++ 后缀的低效性++;/--如何优化STL迭代器的运算符?,c++,iterator,post-increment,C++,Iterator,Post Increment,我知道编译器通常会针对内置类型优化增量/减量运算符的后缀版本(即,不会进行复制),但对于迭代器s,情况是否如此 它们本质上只是重载运算符,可以以多种方式实现,但由于它们的行为是严格定义的,是否可以对它们进行优化?如果可以,是否可以由任何/许多编译器进行优化 #include <vector> void foo(std::vector<int>& v){ for (std::vector<int>::iterator i = v.begin();
迭代器
s,情况是否如此
它们本质上只是重载运算符,可以以多种方式实现,但由于它们的行为是严格定义的,是否可以对它们进行优化?如果可以,是否可以由任何/许多编译器进行优化
#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;
}
}
#包括
void foo(标准::向量和向量){
for(std::vector::iterator i=v.begin();
i!=v.end();
i++{//编译器是否会对此进行优化?
*i+=20;
}
}
在GNU GCC的STL实现(版本4.6.1)上的std::vector
的特定情况下,我认为在足够高的优化级别上不会有性能差异
向量
上的前向迭代器的实现由提供。让我们看看它的构造函数和后缀++
操作符:
explicit
__normal_iterator(const _Iterator& __i) : _M_current(__i) { }
__normal_iterator
operator++(int)
{ return __normal_iterator(_M_current++); }
及其在向量中的实例化:
typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
如您所见,在这两种情况下输出的程序集完全相同
当然,对于自定义迭代器或更复杂的数据类型,情况未必如此。但是,对于向量,前缀和后缀(不捕获后缀返回值)似乎具有相同的性能。这是一个有趣的问题,即使它是一个微优化。除非迭代器操作有副作用,否则编译器可以按照假设规则优化后增量版本。它是否正确取决于编译器。Indebug构建时,它可能不会被优化,那么为什么要让调试变慢呢?我不认为只有在你真正需要的时候才养成使用后增量的好习惯有什么问题。@Gene我同意,而且我有随时使用前增量的习惯。我只是好奇:)很好的分析。我希望任何好的优化编译器都能执行同样的操作。谢谢你的回答。我怀疑@Mark是对的,尽管我对其他编译器很好奇。也可以用其他编译器测试:)但是这是有效的测试吗?您确定当优化器看到结果被忽略时,它不仅仅将it++
替换为++it
?考虑到后缀++
在for
循环中的广泛使用,这似乎是一个很好的优化。(不要笑;我看到优化器用put(“foo”);
替换printf(“foo\n”);
)这正是我看到的,也是我测试的目的:)显然,如果你真的将it++
的返回值存储在某个地方,它必须做一些额外的工作才能做到这一点;这同样适用于x=++it
。问题是,优化器是否足够聪明,在不需要的时候不做额外的工作。
#include <vector>
void test_prefix(std::vector<int>::iterator &it)
{
++it;
}
void test_postfix(std::vector<int>::iterator &it)
{
it++;
}
.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