Правильный ли следующий код (func1 ()), если он должен возвращать i? Я помню, как где-то читал, что возникает проблема при возврате ссылки на локальную переменную. Чем он отличается от func2 ()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int& i = * new int;
Ответы:
Этот фрагмент кода:
не будет работать, потому что вы возвращаете псевдоним (ссылку) на объект, время жизни которого ограничено областью действия вызова функции. Это означает, что однажды
func1()
возвращается,int i
умирает, делая ссылку, возвращенную функцией, бесполезной, потому что теперь она ссылается на несуществующий объект.Вторая версия работает, потому что переменная размещается в бесплатном хранилище, которое не привязано к времени жизни вызова функции. Однако вы несете ответственность за
delete
выделенныйint
.Обычно вы помещаете указатель в какой-либо класс RAII и / или фабричную функцию, чтобы вам не приходилось делать
delete
это самостоятельно.В любом случае вы можете просто вернуть само значение (хотя я понимаю, что приведенный вами пример, вероятно, был надуманным):
Обратите внимание, что совершенно нормально возвращать большие объекты таким же образом, как и
func3()
примитивные значения, потому что практически каждый компилятор в настоящее время реализует ту или иную форму оптимизации возвращаемого значения :Интересно, что привязка временной ссылки к константной ссылке совершенно допустима в C ++ .
источник
int* p = func2(); delete p;
Теперь, когда вы удалили 'p', означает ли это, что память, выделенная «внутри» определения функцииfunc2()
, также была удалена?func2()
и выпущена снаружи в следующей строке. Это довольно подверженный ошибкам способ работы с памятью, как я уже сказал, вместо этого вы бы использовали какой-нибудь вариант RAII. Кстати, вы говорите так, будто изучаете C ++. Я рекомендую взять хорошую вводную книгу по C ++, чтобы учиться. Кроме того, для справки в будущем, если у вас есть вопрос, вы всегда можете опубликовать его на сайте Stack Overflow. Комментарии не предназначены для того, чтобы задавать совершенно новые вопросы.Локальная переменная - это память в стеке, эта память не становится автоматически недействительной при выходе из области видимости. Из более глубоко вложенной функции (выше в стеке в памяти) доступ к этой памяти совершенно безопасен.
Однако, когда функция возвращается и завершается, все становится опасным. Обычно память не удаляется и не перезаписывается при возврате, то есть память по этому адресу все еще содержит ваши данные - указатель кажется действительным.
Пока другая функция не создаст стек и не перезапишет его. Вот почему это может работать какое-то время - а затем внезапно перестает функционировать после того, как один особенно глубоко вложенный набор функций или функция с действительно огромными размерами или множеством локальных объектов снова достигает этой стековой памяти.
Может случиться так, что вы снова достигнете той же части программы и перезапишете свою старую локальную переменную функции новой переменной функции. Все это очень опасно, и от этого следует отказаться. Не используйте указатели на локальные объекты!
источник
Следует помнить об этих простых правилах, и они применяются как к параметрам, так и к возвращаемым типам ...
Для каждого есть свое время и место, поэтому обязательно познакомьтесь с ними. Локальные переменные, как вы здесь показали, ограничены временем, в течение которого они локально активны в области действия функции. В вашем примере наличие типа возврата
int*
и возврата&i
было бы одинаково неверным. В таком случае тебе лучше сделать это ...Это напрямую изменит значение переданного вами параметра. А этот код ...
не стал бы. Это просто изменит значение
oValue
local для вызова функции. Причина этого в том, что вы фактически меняете только «локальную» копиюoValue
, а неoValue
саму себя.источник