Я думаю, что большая путаница возникает из-за того, что не сообщается, что подразумевается под , переданным ссылкой . Когда некоторые люди говорят, что передается по ссылке , они обычно имеют в виду не сам аргумент, а объект, на который ссылается . Некоторые говорят, что передача по ссылке означает, что объект не может быть изменен в вызываемом объекте. Пример:
struct Object {
int i;
};
void sample(Object* o) { // 1
o->i++;
}
void sample(Object const& o) { // 2
// nothing useful here :)
}
void sample(Object & o) { // 3
o.i++;
}
void sample1(Object o) { // 4
o.i++;
}
int main() {
Object obj = { 10 };
Object const obj_c = { 10 };
sample(&obj); // calls 1
sample(obj) // calls 3
sample(obj_c); // calls 2
sample1(obj); // calls 4
}
Некоторые люди утверждают, что 1 и 3 передаются по ссылке, а 2 - по значению. Другая группа людей говорит, что все, кроме последнего, передаются по ссылке, потому что сам объект не копируется.
Я бы хотел дать здесь определение того, что я называю передать по ссылке . Общий обзор этого можно найти здесь: Разница между передачей по ссылке и передачей по значению . Первый и последний передаются по значению, а средние два передаются по ссылке:
sample(&obj);
// yields a `Object*`. Passes a *pointer* to the object by value.
// The caller can change the pointer (the parameter), but that
// won't change the temporary pointer created on the call side (the argument).
sample(obj)
// passes the object by *reference*. It denotes the object itself. The callee
// has got a reference parameter.
sample(obj_c);
// also passes *by reference*. the reference parameter references the
// same object like the argument expression.
sample1(obj);
// pass by value. The parameter object denotes a different object than the
// one passed in.
Я голосую за следующее определение:
Аргумент (1.3.1) передается по ссылке, если и только если соответствующий параметр вызываемой функции имеет ссылочный тип и , параметр ссылки привязывается непосредственно к выражению аргумента (8.5.3 / 4). Во всех остальных случаях мы имеем дело с передачей по значению.
Это означает, что следующее передается по значению:
void f1(Object const& o);
f1(Object()); // 1
void f2(int const& i);
f2(42); // 2
void f3(Object o);
f3(Object()); // 3
Object o1; f3(o1); // 4
void f4(Object *o);
Object o1; f4(&o1); // 5
1
передается по значению, поскольку оно не связано напрямую. Реализация может скопировать временную и затем привязать эту временную ссылку. 2
передается по значению, потому что реализация инициализирует временный литерал, а затем привязывается к ссылке. 3
передается по значению, поскольку параметр не имеет ссылочного типа. 4
передается по значению по той же причине. 5
передается по значению, поскольку параметр не имеет ссылочного типа. Следующие случаи передаются по ссылке (по правилам 8.5.3 / 4 и др.):
void f1(Object *& op);
Object a; Object *op1 = &a; f1(op1); // 1
void f2(Object const& op);
Object b; f2(b); // 2
struct A { };
struct B { operator A&() { static A a; return a; } };
void f3(A &);
B b; f3(b); // passes the static a by reference