push_back является более дорогой операцией, чем доступ на основе индекса, даже если резервирование было заранее выполнено резервом.
- push_back должно позаботиться о указателе конца, чтобы векторный размер можно было правильно вычислить
- push_back проверит наличие необходимости в реальной операции. По сути, прогноз ветвления.
- push_back приведет к тому, что копирование (или перемещение) значения будет отодвинуто назад. В случае int, это не должно вызывать разницы в производительности.
Если вы видите преобразование сборки (взятое из рассматриваемой ссылки на Godbolt), операция индекса - это не ветвящаяся последовательность нескольких ходов и операция сдвига, в то время как push_back гораздо более сложный. В долгосрочной перспективе l oop (1000000 в данном примере) эта разница будет иметь значение. Уровень оптимизации компилятора может определенно влиять на разницу.
Для оператора индекса []
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rax, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rax]
mov rdx, QWORD PTR [rbp-16]
sal rdx, 2
add rax, rdx
pop rbp
ret
Для push_back
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rax, QWORD PTR [rbp-8]
mov rdx, QWORD PTR [rax+8]
mov rax, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rax+16]
cmp rdx, rax
je .L73
mov rax, QWORD PTR [rbp-8] // When allocation is not needed
mov rcx, QWORD PTR [rax+8]
mov rax, QWORD PTR [rbp-8]
mov rdx, QWORD PTR [rbp-16]
mov rsi, rcx
mov rdi, rax
call void std::allocator_traits<std::allocator<int> >::construct<int, int const&>(std::allocator<int>&, int*, int const&)
mov rax, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rax+8]
lea rdx, [rax+4]
mov rax, QWORD PTR [rbp-8]
mov QWORD PTR [rax+8], rdx
jmp .L75
.L73: // When allocation is needed
mov rax, QWORD PTR [rbp-8]
mov rdi, rax
call std::vector<int, std::allocator<int> >::end()
mov rcx, rax
mov rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-8]
mov rsi, rcx
mov rdi, rax
.L75:
nop
leave
ret