Зачем передавать по константной ссылке, а не по значению? - PullRequest
41 голосов
/ 06 апреля 2010

Из того, что я понимаю: когда вы передаете по значению, функция делает локальную копию переданного аргумента и использует это; когда функция заканчивается, она выходит из области видимости. Когда вы передаете по константной ссылке, функция использует ссылку на переданный аргумент, который нельзя изменить. Я не понимаю, однако, почему один выбрал бы один из другого, за исключением ситуации, когда аргумент должен быть изменен и возвращен. Если у вас была функция void, в которой ничего не возвращается, зачем выбирать одну из других?

РЕДАКТИРОВАТЬ: Таким образом, в основном передача по константной ссылке позволяет избежать копирования объекта. Так в каких ситуациях копирование объекта хорошо? Я имею в виду, почему бы просто не использовать постоянные ссылки постоянно, если они постоянно оптимизируют производительность?

Ответы [ 8 ]

48 голосов
/ 06 апреля 2010

Есть два основных соображения. Один - это затраты на копирование переданного объекта, а второй - предположения, которые компилятор может сделать, когда объект является локальным объектом.

например. В первой форме в теле 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 должна выбираться там, где семантика ссылок фактически требуется, или в качестве повышения производительности, только если стоимость потенциального алиасинга будет перевешиваться за счет копирования параметра.

22 голосов
/ 06 апреля 2010

Передача аргументов по значению и, следовательно, их копирование могут быть дорогостоящими - ссылки на const позволяют избежать этого дорогостоящего шага, в то же время обещая вызывающей стороне, что объект не будет изменен.

Обычно фундаментальные типы (int, double, ...) передаются по значению, а типы классов передаются по константной ссылке.

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

4 голосов
/ 06 апреля 2010

Создание копии объекта может сильно повлиять на производительность в некоторых случаях. Рассмотрим функцию, аргумент которой будет std::vector<long>, и вы хотите передать вектор с 1 миллионом элементов. В этом случае вы захотите использовать константную ссылку для передачи по значению. В этом SO вопросе вы можете найти простое общее правило для вашего вопроса.

2 голосов
/ 28 ноября 2014

Массив не может быть передан по значению, поэтому сейчас самое время использовать указатель const.

2 голосов
/ 06 апреля 2010

Из-за преимуществ производительности вы получите. Допустим, у вас есть большой объект (с точки зрения размера в байтах). Теперь, если вы передаете этот объект по значению в функцию, необходимо создать ненужную копию, однако вы можете получить тот же эффект, передав константную ссылку на сам объект, не создавая копию. Поскольку ссылка обычно хранится в виде указателя под капотами, стоимость передачи ссылки составляет всего sizeof(pointer).

2 голосов
/ 06 апреля 2010

Передача аргумента по значению накладывается на копию объекта, передаваемого в функцию.

Возможно, объект не подлежит копированию, и ваш выбор ограничен.

2 голосов
/ 06 апреля 2010

Иногда создание копии объекта может быть дорогостоящим, поэтому передача по константной ссылке позволит избежать необходимости делать эту копию. В противном случае я бы сказал, что вам следует просто передавать по значению, если это то, что семантически требуется.

1 голос
/ 06 апреля 2010

К избегайте создания ненужной копии , что повышает производительность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...