Примечание: я отмечаю этот Python и C ++, потому что я видел примеры в обоих, но вопрос не зависит от языка.
У метода функции или класса, который модифицирует объект, есть два варианта: изменить данные непосредственно в рассматриваемом объекте или создать новую копию и вернуть ее, не трогая оригинал. Как правило, вы можете узнать, что есть что, посмотрев на то, что возвращается из функции.
Иногда вы найдете функцию, которая пытается выполнить оба действия, изменить исходный объект и затем вернуть копию или ссылку на этот объект. Есть ли когда-нибудь случай, когда это дает какое-то преимущество перед тем, как делать только одно или другое?
Я видел пример Свободный интерфейс или же Метод цепочки это полагается на возвращение ссылки на объект, но это похоже на особый случай, который должен быть очевиден в контексте.
Мой первый плохой пример исходит прямо из Документация Python и иллюстрирует проблему изменяемых параметров по умолчанию. Для меня этот пример нереалистичен: если функция изменяет свой параметр, тогда не имеет смысла иметь значение по умолчанию, и если она возвращает копию, то копия должна быть сделана до того, как произойдут какие-либо изменения. Проблема существует только потому, что она пытается сделать оба.
def f(a, L=[]):
L.append(a)
return L
Второй пример взят из Microsoft C ++ в CStringT::MakeUpper
функция. Документация говорит это о возвращаемом значении:
Возвращает копию строки, но все заглавные буквы.
Это заставляет ожидать, что оригинал остается неизменным. Часть проблемы заключается в том, что документация вводит в заблуждение, если вы посмотрите на прототип, то обнаружите, что он возвращает ссылка в строку. Вы не заметите это, если не присмотритесь, и присвоение результата новой строке компилируется без ошибок. Сюрприз приходит позже.
C ++ Пример Inc / Dec оператор
// Pre-Increment: Create a new object for return and modify self.
myiterator operator++(int) {myiterator tmp(*this); operator++(); return tmp;}// Post-Increment: modify self and return a reference
myiterator& operator++() {/* Do Stuff*/ return *this;}
В C ++ есть несколько очевидных примеров, когда вы хотите изменить объект и вернуть ссылку:
Назначение:
T & T::operator=(T && rhs)
{
ptr = rhs.ptr;
rhs.ptr = nullptr;
return *this;
}
Этот изменяет как сам объект, так и аргумент, и возвращает ссылку на себя. Таким образом, вы можете написать a = b = c;
,
IOStreams:
std::ostream & operator<<(std::ostream & os, T const & t)
{
os << t->ptr;
return os;
}
Опять же, это позволяет цепочку операций, std::cout << t1 << t2 << t3;
или типичный «извлечь и проверить» if (std::cin >> n) { /* ... */ }
,
По сути, возвращение ссылки на один из входных объектов всегда служит для цепных вызовов или для оценки результирующего состояния в той или иной форме, и для этого есть несколько полезных сценариев.
С другой стороны, изменив аргумент, а затем вернув копия объекта представляется менее полезным.