Как обстоят дела с временными объектами и ссылками? - PullRequest
4 голосов
/ 05 мая 2011

Часто можно прочитать, что вы не можете привязать нормальную ссылку lvalue к временному объекту. Из-за этого часто можно увидеть методы класса A, принимающие const A & в качестве параметра, когда они не хотят включать копирование. Однако такая конструкция полностью легальна:

double& d = 3 + 4;

, поскольку он не привязывает временный объект 3 + 4 к ссылке d, а скорее инициализирует ссылку с объектом 3 + 4. Как сказано в стандарте, только если значение не относится к типу или ссылке (или унаследовано), ссылка выиграла не может быть инициализирован с использованием объекта, полученного из временного объекта с использованием преобразования или sth (т.е. другого временного объекта). Вы можете видеть это в этом случае:

int i = 2;
double & d = i;

Это недопустимо, потому что я не двойного типа и не наследуется от него. Однако это означает, что временные ссылки могут быть связаны с ссылками - но действительно ли это обязательно? Разве это не создание нового объекта с использованием конструктора копирования с временным объектом в качестве параметра?

Поэтому, как мне кажется, смысл использования методов, принимающих const A & param вместо A &, заключается не в том, что во втором случае такой метод не сможет принимать в качестве параметра временный объект типа A (потому что он будет), а потому, что он включает конструктор копирования (как если бы параметр имел тип A). Я прав?

Ответы [ 5 ]

7 голосов
/ 05 мая 2011

Во-первых, как уже говорили другие, двойной & d = 3 + 4; не законно C ++; если ваш компилятор принимает это и заявляет компилировать C ++, это ошибка в компиляторе. (Обратите внимание, что большинство компиляторов C ++ не претендуют на компиляцию C ++, если вы не дадите их специальные опции, -std=c++98 в случае g ++, для пример.)

Во-вторых, мотивация для этого правила исходит из опыта. Рассмотрим следующий пример:

void
incr( int& i )
{
    ++ i;
}

unsigned x = 2;
incr( x );  //  Implicit conversion of unsigned to int
            //  creates a temporary.
std::cout << x << std::endl;
            //  and x is still equal 2 here.

Оригинальная реализация ссылок не имела этого ограничение; Вы можете инициализировать любую ссылку с временный характер. Фактический опыт показал, что это слишком подвержено ошибкам, поэтому ограничение, требующее ссылки на const, было представил. (Примерно в 1988 или 1989 году, так что сегодня нет оправданий для компилятора, чтобы не применять его.)

Обратите внимание, что часто можно услышать, что привязка временного к Ссылка const продлевает время жизни временного. Это очень вводит в заблуждение: использование временного для инициализации ссылки расширяет время жизни временного (за некоторыми исключениями), но время жизни не увеличивается, если эта ссылка используется для инициализации другие ссылки, хотя временный также связан с эти ссылки.

6 голосов
/ 05 мая 2011

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

void method( Object x );

Это копирует-конструирует Object из фактического аргумента. Любые изменения, сделанные в x внутри функции, теряются, когда функция завершается, аргумент функции не изменяется.

Но вы не хотите оплачивать стоимость копирования.

void method( Object & x );

Это не копирование-конструирование Object из фактического аргумента, но x ссылается на аргумент, т.е. любые изменения, сделанные в x внутри функции, действительно сделано для самого аргумента.

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

void method( const Object & x );

Это не копирование-конструирование Object из фактического аргумента, и x нельзя изменить внутри функции .

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

Вы не можете передать временный объект в качестве аргумента во второй вариант (см. Ответ Унаперссона), потому что не будет изменяемого объекта, на который можно сослаться, но поскольку эта функция громко объявляет, что он будет изменять аргумент (так как он объявлен как неконстантная ссылка), передача временного аргумента в любом случае бессмысленна.

1 голос
/ 05 мая 2011

double& d = 3 + 4; является не полностью законным, на самом деле он не будет принят компилятором, совместимым со стандартом.Результат 3+4 является временным типом int - поэтому он может быть связан только с константной ссылкой.

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

0 голосов
/ 05 мая 2011

Ссылка может быть инициализирована lvalue того же типа, а 3 + 4 не является lvalue.Так что это не законно.Компилятор MS VC ++ позволяет делать нечто похожее на ваши объекты, но это не стандартно.

0 голосов
/ 05 мая 2011
void f( int & n ) {
}

int main() {
    f( 1 + 2 );
}

Не требуется создание копии, но временное связывание не будет. Ошибка с g ++:

неверная инициализация неконстантных ссылка типа int & из rvalue типа 'int'

...