Ссылка возврата C ++, объявленная в области видимости функции

Возможный дубликат:
Можно ли получить доступ к памяти локальной переменной вне ее области?

Я видел функцию, когда делал некоторый обзор кода.

wchar_t* GetString(HINSTANCE hInstance, UINT SID)
{
wchar_t buf[2048] = {0};
LoadStringW(hInstance, SID, buf, sizeof(buf)/sizeof(wchar_t));
return &buf[0];
}

void SomeWork()
{
std::wstring str( GetString(hInst, 123) );
}

я думал ЬиЕ должен быть уничтожен сразу после возврата функции,
так указатель &buf [0] может быть недействительным.
Но, кажется, работает нормально, как это работает?
И это хороший дизайн?
Благодарю.

1

Решение

я думал ЬиЕ должен быть уничтожен сразу после возврата функции, поэтому
указатель &buf[0] может быть недействительным.

Ваши мысли на 100% верны.

Но, кажется, работает нормально, как это работает?

Это «работает», потому что часть стека вызовов, которая содержит buf Случайно, массив не переписал свое содержимое к тому моменту, когда вы его используете.

Но это неопределенное поведение, и неопределенное поведение означает все может случиться, и это может включать в себя «вызов Армагеддона» и / или «просто отлично работает». Тебе просто повезло на этот раз.

И это хороший дизайн?

Нет, это ужасный дизайн. К счастью, есть простое исправление: просто верните std::wstring сам.

std::wstring GetString(HINSTANCE hInstance, UINT SID)
{
wchar_t buf[2048] = {0};
LoadStringW(hInstance, SID, buf, sizeof(buf)/sizeof(wchar_t));
return std::wstring(buf);
}

void SomeWork()
{
std::wstring str = GetString(hInst, 123);
}

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

Эта конкретная оптимизация называется оптимизация возвращаемого значения (RVO). Если ваш компилятор C ++ не выполняет RVO, даже если он установлен на самом высоком уровне оптимизации, получите другой.

5

Другие решения

Нет, это серьезный недостаток. Возвращение указателя или ссылки на локальный объект неопределенное поведение. Это означает, что все может произойти, включая начало Второй мировой войны. В вашем случае неопределенное поведение точно так же, как оно «работает нормально». По счастливой случайности

3

Теоретически, это неопределенное поведение, что означает что-нибудь может случиться, в том числе иногда работать (по-видимому) правильно. Однако быть неопределенным означает, что нет способа гарантировать, что он всегда будет работать.

Причина, по которой он работает сейчас, заключается в том, что память, измененная GetString не был изменен каким-либо другим кодом, выполняемым к тому времени, когда вы его прочитали. Другими словами, вам повезло.

1

Я думал, что buf должен быть уничтожен сразу после возврата функции, поэтому указатель &buf [0] может быть недействительным.

Правильно. Время жизни buf кончено; его память могла или не могла быть сделана недоступной или повторно использована для другого объекта; и любой доступ к нему дает неопределенное поведение.

Но, кажется, работает нормально, как это работает?

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

И это хороший дизайн?

Конечно, нет. Вы полагаетесь на неопределенное поведение, и ваш код может перестать работать по многим причинам — изменение платформы или компилятора, добавление еще одного вызова функции в ваш код или сдвиг фазы Луны.

Я бы вернул std::wstring,

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector