2016-09-05 1 views
0

Если я передаю контейнер по постоянной ссылке, есть ли смысл объявить константу ссылки в цикле диапазона, или будут элементы в цикл автоматически присуще этому свойству?для цикла диапазона с аргументом const и аргументом, когда сам итеративный передается аргументом const & аргумент

т.е.

int foo(std::vector<int> const& vec) { 
    for (int const& el : vec) 
     // do something... 
} 

является выше эквивалентно:

int foo(std::vector<int> const& vec) { 
    for (int el : vec) 
     // do something... 
} 
+0

У вас не может быть ссылка nonconst. Но во втором примере у вас нет ссылки вообще; Там аргумент просто копируется. – Cubic

+0

@Cubic Я не уверен, что вы имеете в виду, вы можете сказать 'for (int & el: vec) {... modify el here ...}'. Наверное, я спрашиваю, проходите ли вы по ссылке const в функции (таким образом, не копируя контейнер), с чего вы копируете, когда вы не проходите по ссылке в цикле? – learning

+0

Ваш второй цикл имеет 'el', объявленный как' int' вместо 'int &', поэтому он получает копию вместо ссылки. – Cubic

ответ

1

Для тривиального скаляр, как в междунар, константная ссылка только над головой - за кулисами ссылки реализуются с помощью указателей, так ссылка действительно просто указатель, управляемый компилятором, и доступ к ней требует разыменования.

#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, компилятор устранили ссылку.