Будет ли неэффективность постфиксных операторов ++ / - оптимизирована для итераторов STL?
Я знаю, что постфиксные версии операторов инкремента / декремента обычно оптимизируются компилятором для встроенных типов (т. е. копия не будет сделана), но так ли это для iterator
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;
}
}
1 ответ:
В конкретном случае
std::vector
на реализации STL GNU GCC (версия 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++); }
И его экземпляр в
vector
:typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
Как вы можете видеть, он внутренне выполняет постфиксное приращение для обычного указателя, а затем передает исходное значение через собственный конструктор, который сохраняет его в локальном элементе. Этот код должен быть тривиальным, чтобы устранить его с помощью анализа мертвых значений.
Но оптимизирован ли он на самом деле? Давайте выясним. Код теста:
#include <vector> void test_prefix(std::vector<int>::iterator &it) { ++it; } void test_postfix(std::vector<int>::iterator &it) { it++; }
Выходной узел (ВКЛ
-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
vector
в частности, префикс и постфикс (без захвата возвращаемого значения postfix) имеют одинаковую производительность.