Это немного субъективно, я думаю; Я не уверен, что мнение будет единодушным (я видел много фрагментов кода, где возвращаются ссылки).
В соответствии с комментарием к этому вопросу, который я только что спросил, относительно инициализации ссылок , возврат ссылки может быть злым, потому что, [насколько я понимаю], легче пропустить его удаление, что может привести к утечкам памяти.
Это беспокоит меня, так как я следовал примерам (если я не представляю себе что-то) и делал это в нескольких местах ... Я неправильно понял? Это зло? Если так, то насколько злой?
Я чувствую, что из-за моего смешанного мешка с указателями и ссылками, в сочетании с тем, что я новичок в C ++, и полной путаницы в отношении того, что использовать, когда мои приложения должны быть адом утечки памяти ...
Кроме того, я понимаю, что использование интеллектуальных / общих указателей обычно считается лучшим способом избежать утечек памяти.
Ответы:
В общем, возвращение ссылки совершенно нормально и происходит постоянно.
Если ты имеешь ввиду:
Это все виды зла. Выделенный стек
i
исчезнет, и вы ни на что не ссылаетесь. Это тоже злоПотому что теперь клиент должен в конечном итоге сделать странное:
Обратите внимание, что ссылки на rvalue по-прежнему являются просто ссылками, поэтому все злые приложения остаются неизменными.
Если вы хотите выделить что-то, что выходит за рамки функции, используйте умный указатель (или вообще контейнер):
И теперь клиент хранит умный указатель:
Ссылки также подходят для доступа к вещам, где вы знаете, что время жизни открыто на более высоком уровне, например:
Здесь мы знаем, что можно возвращать ссылку,
i_
потому что все, что вызывает нас, управляет временем жизни экземпляра класса, поэтомуi_
будет жить по крайней мере так долго.И, конечно же, нет ничего плохого в том, чтобы просто:
Если время жизни должно быть предоставлено вызывающей стороне, а вы просто вычисляете значение.
Резюме: можно вернуть ссылку, если время жизни объекта не закончится после вызова.
источник
return new int
.Нет, нет, тысячу раз нет.
Зло - это ссылка на динамически размещенный объект и потеря первоначального указателя. Когда вы
new
объект, вы берете на себя обязательство иметь гарантиюdelete
.Но взгляните, например
operator<<
: это должно вернуть ссылку, илине сработает
источник
Вы должны вернуть ссылку на существующий объект, который не исчезает немедленно и в котором вы не собираетесь передавать права собственности.
Никогда не возвращайте ссылку на локальную переменную или что-то подобное, потому что на нее не будет ссылки.
Вы можете вернуть ссылку на что-то независимое от функции, которое, как вы ожидаете, не вызовет функцию, которая возьмет на себя ответственность за удаление. Это касается типичной
operator[]
функции.Если вы создаете что-то, вы должны вернуть либо значение, либо указатель (обычный или умный). Вы можете возвращать значение свободно, так как оно входит в переменную или выражение в вызывающей функции. Никогда не возвращайте указатель на локальную переменную, так как она исчезнет.
источник
Я считаю, что ответы не являются удовлетворительными, поэтому я добавлю свои два цента.
Давайте проанализируем следующие случаи:
Ошибочное использование
Это явно ошибка
Использование со статическими переменными
Это правильно, потому что статические переменные существуют на протяжении всей жизни программы.
Это также довольно часто встречается при реализации шаблона Singleton
Использование:
операторы
Контейнеры стандартной библиотеки сильно зависят от использования операторов, которые, например, возвращают ссылку
может использоваться в следующих
Быстрый доступ к внутренним данным
Есть моменты, когда & могут быть использованы для быстрого доступа к внутренним данным
с использованием:
ОДНАКО, это может привести к ловушке, такой как это:
источник
true
:If((a*b) == (c*d))
Container::data()
Реализация должна читатьсяreturn m_data;
Это не зло. Как и многие вещи в C ++, это хорошо, если используется правильно, но есть много подводных камней, о которых вы должны знать при использовании (например, возвращая ссылку на локальную переменную).
Есть хорошие вещи, которые могут быть достигнуты с ним (например, map [name] = "hello world")
источник
map[name] = "hello world"
?HashMap<String,Integer>
в Java? : PНе правда. Возврат ссылки не подразумевает семантику владения. То есть только потому, что вы делаете это:
... не означает, что теперь у вас есть память, на которую ссылается v;
Тем не менее, это ужасный код:
Если вы делаете что-то вроде этого, потому что «вам не нужен указатель на этот экземпляр», то: 1) просто разыменуйте указатель, если вам нужна ссылка, и 2) вам в конечном итоге понадобится указатель, потому что вы должны соответствовать новый с удалением, и вам нужен указатель для вызова удаления.
источник
Есть два случая:
константная ссылка - хорошая идея, иногда, особенно для тяжелых объектов или прокси-классов, оптимизация компилятора
неконстантная ссылка - плохая идея иногда нарушает инкапсуляцию
Оба имеют одну и ту же проблему - потенциально могут указывать на уничтоженный объект ...
Я бы порекомендовал использовать умные указатели для многих ситуаций, когда вам требуется возвращать ссылку / указатель.
Также обратите внимание на следующее:
Существует формальное правило - Стандарт C ++ (раздел 13.3.3.1.4, если вам интересно) гласит, что временная ссылка может быть связана только с константной ссылкой - если вы пытаетесь использовать неконстантную ссылку, компилятор должен пометить это как ошибка.
источник
Мало того, что это не зло, это иногда важно. Например, было бы невозможно реализовать оператор [] в std :: vector без использования ссылочного возвращаемого значения.
источник
operator[]
для контейнера без использования ссылки ... иstd::vector<bool>
делает. (И создает настоящий беспорядок в процессе)::std::vector<bool>
вы упомянули).std::vector<T>
в шаблоне кода нарушено, еслиT
может бытьbool
, потомуstd::vector<bool>
что поведение очень отличается от других экземпляров. Это полезно, но ему нужно было дать собственное имя, а не специализациюstd::vector
.Дополнение к принятому ответу:
Я бы сказал, что этот пример нехорош и его следует избегать, если это возможно. Зачем? Это очень легко закончить висячей ссылкой .
Чтобы проиллюстрировать это на примере:
вход в опасную зону:
источник
ссылка на возврат обычно используется в C ++ для перегрузки операторов для больших объектов, поскольку для возврата значения требуется операция копирования (при перегрузке perator мы обычно не используем указатель в качестве возвращаемого значения)
Но обратная ссылка может вызвать проблемы с выделением памяти. Поскольку ссылка на результат будет передана из функции как ссылка на возвращаемое значение, возвращаемое значение не может быть автоматической переменной.
если вы хотите использовать возвращающую ссылку, вы можете использовать буфер статического объекта. например
таким образом, вы можете безопасно использовать возвращаемую ссылку.
Но вы всегда можете использовать указатель вместо ссылки для возврата значения в функцииg.
источник
Я думаю, что использование ссылки в качестве возвращаемого значения функции намного проще, чем использование указателя в качестве возвращаемого значения функции. Во-вторых, всегда было бы безопасно использовать статическую переменную, к которой относится возвращаемое значение.
источник
Лучше всего создать объект и передать его в качестве параметра ссылки / указателя в функцию, которая выделяет эту переменную.
Выделение объекта в функции и возврат его в качестве ссылки или указателя (однако указатель безопаснее) является плохой идеей из-за освобождения памяти в конце функционального блока.
источник
Функция getPtr может получить доступ к динамической памяти после удаления или даже к нулевому объекту. Что может привести к недопустимым исключениям доступа. Вместо этого должны быть реализованы getter и setter и проверен размер перед возвратом.
источник
Функция как lvalue (или возвращение неконстантных ссылок) должна быть удалена из C ++. Это ужасно не интуитивно понятно. Скотт Мейерс хотел min () с таким поведением.
что на самом деле не улучшение
Последнее даже имеет больше смысла.
Я понимаю, что функция как lvalue важна для потоков в стиле C ++, но стоит отметить, что потоки в стиле C ++ ужасны. Я не единственный, кто так думает ... насколько я помню, у Александреску была большая статья о том, как сделать лучше, и я считаю, что boost также попытался создать лучший тип безопасного ввода-вывода.
источник
vector::operator[]
например. Вы бы предпочли написатьv.setAt(i, x)
илиv[i] = x
? Последний намного выше.v.setAt(i, x)
любое время. Это далеко выше.Я столкнулся с реальной проблемой, где это было действительно зло. По сути, разработчик вернул ссылку на объект в векторе. Это было плохо !!!
Все подробности, о которых я писал в Janurary: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html
источник
О ужасном коде:
Так что, действительно, указатель памяти теряется после возврата. Но если вы используете shared_ptr вот так:
Память не теряется после возврата и будет освобождена после назначения.
источник