Разница в том, что с Test(vector<int>& v)
(что, кстати, является lvalue ссылкой) v указывает на исходный объект, а с Test(vector<int> v)
у вас есть копия.В следующем примере кода демонстрируется разница с int
и обычной функцией (обратите внимание, что для int
передача по значению на самом деле быстрее!):
#include <iostream>
int global_i;
void pass_by_value(int i)
{
std::cout << "pass by value:\n";
std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
i++;
std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
global_i++;
std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}
void pass_by_reference(int& i)
{
std::cout << "pass by reference:\n";
std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
i++;
std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
global_i++;
std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}
void pass_by_const_reference(int const& i)
{
std::cout << "pass by const reference:\n";
std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
// i++; not allowed!
// std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
global_i++;
std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}
int main()
{
global_i = 1;
pass_by_value(global_i);
global_i = 1;
pass_by_reference(global_i);
global_i = 1;
pass_by_const_reference(global_i);
}
Вывод этого:
pass by value:
initially: i = 1, global_i = 1
after i++: i = 2, global_i = 1
after global_i++: i = 2, global_i = 2
pass by reference:
initially: i = 1, global_i = 1
after i++: i = 2, global_i = 2
after global_i++: i = 3, global_i = 3
pass by const reference:
initially: i = 1, global_i = 1
after global_i++: i = 2, global_i = 2
Как видите, при вызове по значению аргумент и переданная переменная полностью разделяются.Приращение аргумента не меняет переданную переменную, а приращение переданной переменной не меняет аргумент.С другой стороны, при передаче по ссылке аргумент просто предоставляет доступ к переданной переменной: не имеет значения, какую из них вы увеличиваете, потому что по сути они одинаковы.С передачей по константной ссылке они также одинаковы, но вам не разрешено оспаривать аргумент (хотя есть способы обойти это).Однако аргумент по-прежнему отражает любые изменения переданной переменной.
Это различия в функциональности.Однако есть и другие различия: для передачи по значению и передачи по константной ссылке вы можете использовать значение r, например call_by_value(2)
или call_by_const_reference(2)
.Для вызова по значению очевидно, что происходит: аргумент получает значение 2, и все.Однако для константной ссылки есть ожидаемый объект (например, вы можете взять адрес этого объекта в функции).Поэтому в этом случае создается временный объект.Для вызова по неконстантной ссылке вы не можете передать rvalue.
C ++ 11 добавляет в микс другой тип, а именно ссылки на rvalue.Они обозначены &&
вместо &
.Внутри функции они ведут себя точно так же, как нормальные (lvalue) ссылки, но отличаются тем, что могут быть связаны с rvalue, даже если они не являются const.Более того, если вы используете их как тип возвращаемого значения, выражение вызова будет иметь тип rvalue, как если бы вы вернули значение.В частности, вы не сможете передать результат функции, возвращающей ссылку rvalue, в функцию, ожидающую ссылку lvalue, так же, как вы не могли бы сделать это с литералом 2.