Для тривиального скаляр, как в междунар, константная ссылка только над головой - за кулисами ссылки реализуются с помощью указателей, так ссылка действительно просто указатель, управляемый компилятором, и доступ к ней требует разыменования.
#include <vector>
extern void f1(int);
extern void f2(int const&);
int foo1(std::vector<int> const& v) {
for (int const& val: v) {
f1(val);
f2(val);
}
}
int foo2(std::vector<int> const& v) {
for (int val: v) {
f1(val);
f2(val);
}
}
Assembly output
foo2 производит это:
movl (%rbx), %edi ; val = *it
addq $4, %rbx ; ++it
movl %edi, 12(%rsp) ; save val on stack
call f1(int)
leaq 12(%rsp), %rdi ; load address of saved val
call f2(int const&)
Обратите внимание на leaq
для вызова f2
. Мы взяли простую копию текущего значения вектора в edi
, но затем нам также пришлось вставить его в стек, чтобы мы могли получить адрес для соответствия ссылочному требованию для f2
.
Однако в другом примере, компилятор вполне способен выяснить, что ссылка была не нужна и просто делать правильные вещи:
#include <vector>
#include <atomic>
int total;
int foo1(std::vector<int> const& v) {
for (int const& val: v) {
total += val;
}
}
int foo2(std::vector<int> const& v) {
for (int val: v) {
total += val;
}
}
both functions produce the same code, компилятор устранили ссылку.
У вас не может быть ссылка nonconst. Но во втором примере у вас нет ссылки вообще; Там аргумент просто копируется. – Cubic
@Cubic Я не уверен, что вы имеете в виду, вы можете сказать 'for (int & el: vec) {... modify el here ...}'. Наверное, я спрашиваю, проходите ли вы по ссылке const в функции (таким образом, не копируя контейнер), с чего вы копируете, когда вы не проходите по ссылке в цикле? – learning
Ваш второй цикл имеет 'el', объявленный как' int' вместо 'int &', поэтому он получает копию вместо ссылки. – Cubic