Возврат ссылки на локальную переменную - PullRequest
2 голосов
/ 21 сентября 2011

Почему этот код может успешно выполняться в Code :: block.ИДБ просто сообщает

предупреждение: "ссылка на локальную переменную 'tmp' возвращена",

, но успешно выводит результат "hello world".

#include <iostream>
#include<string>
using namespace std;

const string &getString(const string &s)
{
    string tmp = s;
    return tmp;
}

int main()
{
    string a;
    cout<<getString("hello world")<<endl;
    return 0;
}

Ответы [ 8 ]

2 голосов
/ 21 сентября 2011

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

Доступ к такимсвисающая ссылка вызывает то, что называется «неопределенным поведением», и, к сожалению, «работать как обычно» - это один из видов «неопределенного поведения».Здесь может произойти следующее: std::string сохраняет небольшой статический буфер для небольших строк (в отличие от больших строк, для которых он захватывает память из кучи), а при выходе getString пространство стека, занимаемое этой строкой, не обнуляетсятак что все еще похоже на работу.

Если вы попробуете отладочную сборку или вызовете другую промежуточную функцию (которая будет эффективно перезаписывать пространство стека), она больше не будет работать.

1 голос
/ 21 сентября 2011

Может быть эта ссылка поможет вам.

1 голос
/ 21 сентября 2011

tmp исчезает в тот момент, когда вы возвращаетесь из getString. Использование возвращенной ссылки - неопределенное поведение, поэтому может произойти все что угодно.

Чтобы исправить ваш код, верните строку по значению:

string getString(const string &s)
{
...
1 голос
/ 21 сентября 2011

Вы вызываете неопределенное поведение. Стандарт не сообщает, что происходит в этом случае, однако ваш компилятор обнаружил это.

0 голосов
/ 21 сентября 2011

Как видно из приведенного ниже примера, код просто слегка модифицируется путем вызова goodByeString ().Как и в других ответах, уже упоминавшихся, переменная в getString с именем tmp является локальной.переменная выходит из области видимости, как только функция возвращается.так как он выделен стеком, память все еще остается действительной, когда функция возвращается, но как только стек снова увеличивается, эта часть памяти, где находилась tmp, переписывается с чем-то другим.Тогда ссылка на содержит мусор.

Однако, если вы решите вывести b, так как он не возвращается по ссылке, содержимое остается в силе.

#include <iostream>
#include<string>
using namespace std;

const string &getString(const string &s)
{
  string tmp = s;
  return tmp;
}

string goodByeString(const string &s)
{
  string tmp = "lala";
  tmp += s;
  return tmp;
}

int main()
{
   const string &a = getString("Hello World!\n");
   string b = goodByeString("ciao\n");
   cout << a << endl;
   return 0;
}
0 голосов
/ 21 сентября 2011

Стандарт C ++ говорит, что привязка временного объекта к константной ссылке продлевает время жизни временного объекта до времени жизни самой ссылки.Поэтому код должен работать на любом совместимом со стандартом компиляторе, но, на мой взгляд, сама практика не очень приятна.

Если вы используете вашу строку, которая в настоящее время не используется в вашем примере, как строку a = getString ("HelloМир! ") Вы просто сделаете копию, а в случае const string & a = getString (" Hello World! ") Моя ставка на то, что вы никогда не должны носить временную одежду.

0 голосов
/ 21 сентября 2011

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

const string& garbage = getString("Hello World!");
callSomeFunctionThatUsesALotOfStackMemory();
cout<< garbage << endl;
0 голосов
/ 21 сентября 2011

Ты уверен? Должно быть segfault (это будет с gcc на большинстве платформ). Этот код содержит ошибку, и если вам повезло, и он работает, значит, вы стираете неприятную ошибку под ковром.

Ваша строка возвращается по ссылке, то есть вместо создания новой строки, которая действительна в контексте, в который вы возвращаетесь, указатель на устаревший, разрушенный объект возвращается, что плохо. const string getString... будет использоваться как объявление для типа возвращаемого значения функции.

...