При перегрузке operator=
, вы можете напишите, чтобы вернуть нужный тип. Если вы хотите достаточно плохо, вы можете перегрузить X::operator=
, чтобы вернуть (например) экземпляр некоторого совершенно другого класса Y
или Z
. Это, как правило, высоко нецелесообразно.
В частности, вы обычно хотите поддерживать цепочку operator=
так же, как C. Например:
int x, y, z;
x = y = z = 0;
В таком случае, вы обычно хотите вернуть именующее выражение или RValue типа быть назначен. Это только оставляет вопрос о том, следует ли возвращать ссылку на X, константу ссылки на X или X (по значению).
Возвращение константной ссылки на X, как правило, является плохой идеей. В частности, ссылка на const может быть привязана к временному объекту. Время жизни временного расширения распространяется на время жизни ссылки, к которой привязано, но не рекурсивно к времени жизни того, что может быть назначено. Это облегчает возврат оборванной ссылки - ссылка на const ссылается на временный объект. Время жизни этого объекта распространяется на время жизни ссылки (которая заканчивается в конце функции). К моменту возвращения функции время жизни ссылочного и временного заканчивается, поэтому назначенная ссылка является оборванной ссылкой.
Конечно, возврат неконстантной ссылки не обеспечивает полной защиты от этого, но по крайней мере заставляет вас работать немного усерднее. Вы можете (например) определить некоторые локальные и вернуть ссылку на него (но большинство компиляторов может и будет предупреждать об этом тоже).
Возвращение значения вместо ссылки имеет как теоретические, так и практические проблемы. С теоретической стороны у вас есть базовое разъединение между =
, что обычно означает и что это означает в этом случае. В частности, когда назначение обычно означает «взять этот существующий источник и присвоить его значение этому существующему назначению», это начинает означать нечто большее, как «взять этот существующий источник, создать его копию и присвоить это значение этому существующему назначению. "
С практической точки зрения, особенно до того, как были изобретены ссылки на rvalue, это могло бы оказать значительное влияние на производительность - создание всего нового объекта при копировании A-B было неожиданным и часто довольно медленным. Если бы, например, у меня был небольшой вектор и назначался его более крупному вектору, я ожидал бы, что самое большее, чтобы скопировать элементы небольшого вектора плюс (небольшая) фиксированная накладная плата, чтобы отрегулировать размер вектор назначения.Если вместо этого задействованы два экземпляра, один из источника в темп, другой от временного пункта назначения и (что еще хуже) динамическое распределение для временного вектора, мое ожидание о сложности операции будет полностью уничтожено. Для небольшого вектора время для динамического распределения может быть во много раз выше времени для копирования элементов.
Единственный другой вариант (добавленный в C++ 11) - это вернуть ссылку rvalue. Это может легко привести к неожиданным результатам - привязанное задание, такое как a=b=c;
, может уничтожить содержимое b
и/или c
, что было бы совершенно неожиданным.
Это возвращает возвращаемую нормальную ссылку (а не ссылку на константу или ссылку на rvalue) как единственный вариант, который (разумно) обеспечивает надежную работу большинства людей.
Там нет такого требования. Но если вы хотите придерживаться принципа наименьшего удивления, вы вернете 'A &' так же, как 'a = b' - выражение lvalue, относящееся к' a', в случае 'a' и' b' - ints. – sellibitze
@MattMcNabb Спасибо, что сообщили мне! Сделаю это – bks
Почему мы не можем вернуть 'A *' из оператора присваивания копий? Я предполагаю, что назначение цепочки будет работать правильно. Может ли кто-нибудь помочь понять опасности возврата 'A *', если они есть. –