Есть два основных соображения. Один - это затраты на копирование переданного объекта, а второй - предположения, которые компилятор может сделать, когда объект является локальным объектом.
например. В первой форме в теле f
нельзя предположить, что a
и b
не ссылаются на один и тот же объект; поэтому значение a
должно быть перечитано после любой записи в b
, на всякий случай. Во второй форме a
не может быть изменено посредством записи в b
, так как он является локальным для функции, поэтому эти повторные чтения не нужны.
void f(const Obj& a, Obj& b)
{
// a and b could reference the same object
}
void f(Obj a, Obj& b)
{
// a is local, b cannot be a reference to a
}
Например: в первом примере компилятор может предположить, что значение локального объекта не изменяется при выполнении несвязанного вызова. Без информации о h
компилятор может не знать, не изменился ли объект, на который эта функция имеет ссылку (через параметр ссылки), h
. Например, этот объект может быть частью глобального состояния, которое изменяется с помощью h
.
void g(const Obj& a)
{
// ...
h(); // the value of a might change
// ...
}
void g(Obj a)
{
// ...
h(); // the value of a is unlikely to change
// ...
}
К сожалению, этот пример не чугунный. Можно написать класс, который, скажем, добавляет указатель на себя к глобальному объекту состояния в своем конструкторе, так что даже локальный объект типа класса может быть изменен вызовом глобальной функции. Несмотря на это, все еще есть потенциально больше возможностей для правильной оптимизации для локальных объектов, так как они не могут быть наложены напрямую на переданные ссылки или другие ранее существующие объекты.
Передача параметра по ссылке const
должна выбираться там, где семантика ссылок фактически требуется, или в качестве повышения производительности, только если стоимость потенциального алиасинга будет перевешиваться за счет копирования параметра.