Почему это неверная практика возвращает указатель на локальную переменную или параметр?

Я нашел этот вопрос в своем учебном пособии, и я не уверен, почему было бы плохо возвращать указатель на локальную переменную / параметр. Есть идеи?

Это не столько «плохая практика» (подразумевая, что это может вызвать проблемы), сколько это практика, которая будет абсолютно вызывать неопределенное поведение . Это похоже на разыменование нулевого указателя: не делайте этого и ожидайте, что ваша программа будет вести себя в рамках логики.

Объяснение:

Когда объявляется локальная переменная (включая параметр), ей предоставляется автоматическое хранилище , что означает, что компилятор заботится о распределении памяти для переменной и затем освобождает эту память без каких-либо усилий со стороны программиста.

void foo(int bar) { int baz; } //baz and bar dissappear here 

Когда переменная «время жизни заканчивается (например, когда функция возвращается), компилятор выполняет свое promise, и все автоматические переменные, которые были локальными для функции, уничтожаются. Это означает, что любые указатели на эти переменные теперь указывают на память мусора, которую программа считает «свободной» делать с тем, что она хочет.

При возврате значения это не проблема: программа находит новое место для размещения значения.

 int foo(int bar) { int baz = 6; return baz + bar; //baz + bar copied to new memory location outside of foo } //baz and bar disapear 

Когда вы возвращаете указатель, значение указателя копируется как обычно. Однако указатель все же указывает на то же место, которое теперь мусор :

 int* foo(int bar) { int baz = 6; baz += bar; return &baz; //(&baz) copied to new memory location outside of foo } //baz and bar disapear! &baz is now garbage memory! 

Доступ к этой памяти – это неопределенное поведение, поэтому ваша программа почти наверняка будет плохо себя вести. Например, я однажды стал жертвой этой точной проблемы , и, хотя моя программа не сработала или не завершилась, мои переменные начали деgradleировать в значения мусора, поскольку компилятор переписывал «свободную» память.

Потому что это приведет к неопределенному поведению в вашей программе.

Если вы вернете указатель на локальную переменную после возвращения функции, она выходит за frameworks. С тех пор это неопределенное поведение, если вы обращаетесь к возвращенному указателю.

После возвращения функции локальные переменные и параметры, которые были в стеке, были де-распределены. Они все еще могут существовать, но нет никаких гарантий, и когда что-то решает использовать стек, они, безусловно, будут удалены.

Используя диаграмму из WP:

Структурная диаграмма

Указатель стека вверху – это то, где новые переменные можно безопасно распределять и размещать (например, при вызове функции). Когда функция (например, DrawLine) возвращается, они удаляются из стека (указатель стека только увеличивается, поэтому он больше не указывает на внеочередную область, зеленый, переменные). Все, что приходит позже, выделяет и использует пространство стека, уничтожит старые значения.

Локальная переменная сохраняется в стеке. Значения, хранящиеся в стеке, уничтожаются после выхода из функции / кода (т. Е. Вы достигаете конца функции – технически они могут длиться дольше, но это еще одно обсуждение). Поэтому указатель (который указывает на адрес, в частности, место в памяти) указывает на значение, которое может больше не существовать.

Поскольку адрес этой переменной принадлежит стеку, из которого он был создан. Ничего больше. После того, как вы return , эта активационная запись будет очищена, и все, что было ранее, теперь не определено.