Когда вы перегружаете operator=
, вы можете записать его, чтобы вернуть любой тип, который вы хотите.Если вы хотите достаточно сильно, вы можете перегрузить X::operator=
, чтобы вернуть (например) экземпляр какого-то совершенно другого класса Y
или Z
.Как правило, это крайне нецелесообразно.
В частности, вы обычно хотите поддерживать цепочку operator=
, как это делает C.Например:
int x, y, z;
x = y = z = 0;
В этом случае вы обычно хотите вернуть lvalue или rvalue типа, которому назначен.Это оставляет только вопрос о том, возвращать ли ссылку на X, постоянную ссылку на X или X (по значению).
Возвращение постоянной ссылки на X, как правило, плохая идея.В частности, константная ссылка может привязываться к временному объекту.Время жизни временного объекта распространяется на время жизни ссылки, к которой он привязан, но не рекурсивно на время жизни того, что может быть назначено.Это позволяет легко вернуть висячую ссылку - ссылка const привязывается к временному объекту.Время жизни этого объекта распространяется на время жизни ссылки (которая заканчивается в конце функции).К тому времени, когда функция вернется, время жизни ссылки и временного значения закончится, поэтому назначенная ссылка будет зависшей.
Конечно, возврат неконстантной ссылки не обеспечивает полной защиты от этого, нопо крайней мере, заставляет вас работать немного усерднее.Вы все еще можете (например) определить некоторое локальное и вернуть ссылку на него (но большинство компиляторов тоже могут и будут предупреждать об этом).
Возврат значения вместо ссылки имеет как теоретические, так и практические проблемы.С теоретической точки зрения, у вас есть основное разъединение между =
обычно означает и что это означает в этом случае.В частности, когда назначение обычно означает «взять этот существующий источник и присвоить его значение этому существующему месту назначения», оно начинает означать нечто более похожее на «взять этот существующий источник, создать его копию и присвоить это значение этому существующему месту назначения»."
С практической точки зрения, особенно до изобретения ссылок на значения, это может оказать существенное влияние на производительность - создание всего нового объекта в процессе копирования А в В было неожиданным и часто довольно медленным.Если, например, у меня был маленький вектор, и я назначил его большему вектору, я бы ожидал, что самое большее потребуется время, чтобы скопировать элементы малого вектора плюс (небольшие) фиксированные накладные расходы, чтобы отрегулировать размервектор назначения.Если бы вместо этого потребовалось две копии, одна от источника к температуре, другая от температуры к месту назначения и (что еще хуже) динамическое распределение для временного вектора, я ожидал бы сложности операции полностью уничтожено.Для небольшого вектора время динамического выделения может легко быть во много раз больше, чем время для копирования элементов.
Единственным другим вариантом (добавленным в C ++ 11) будет возвращение ссылки на rvalue.,Это может легко привести к неожиданным результатам - цепочечное присваивание, такое как a=b=c;
, может уничтожить содержимое b
и / или c
, что будет довольно неожиданным.
Это оставляет возврат нормальной ссылки (не ссылка на const или ссылка на rvalue) как единственный вариант, который (разумно) надежно производит то, что обычно хочет большинство людей.