可能重复:
Can a local variable's memory be accessed outside its scope?
我在做一些代码审查时看到了一个函数。
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 应该在函数返回后立即销毁, 因此指针& buf [0]可能无效。 但似乎工作正常,它是如何工作的? 这是一个很好的设计吗? 感谢。
答案 0 :(得分:5)
我认为 buf 应该在函数返回后立即销毁,所以 指针
&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 ++编译器也会优化这种情况。
此特定优化称为return value optimization (RVO)。如果您的C ++编译器即使在设置为最高优化级别时也不执行RVO,请再次使用它。
答案 1 :(得分:3)
没有。这是严重的缺陷。返回指针或对本地对象的引用是未定义的行为。这意味着一切都会发生,包括首发WWIII。在你的情况下,未定义的行为就像“工作正常”一样。幸运的是。
答案 2 :(得分:1)
从理论上讲,这是未定义的行为,这意味着任何都可能发生,包括有时正常工作(显然)。但是,未定义意味着无法保证它始终有效。
它现在似乎工作的原因是因为GetString
修改的内存未被您读取它时执行的任何其他代码修改。换句话说,你很幸运。
答案 3 :(得分:1)
我认为函数返回后应立即销毁buf,因此指针& buf [0]可能无效。
这是对的。 buf
的生命周期结束了;它的内存可能已经或可能没有被无法访问或被重用于另一个对象;任何对它的访问都会给出不确定的行为。
但它似乎工作正常,它是如何工作的?
因为在许多平台上,自动变量存储在堆栈中,并且函数的堆栈内存在函数返回时不会变得不可访问。这意味着(无效的悬空引用)变量通常仍会显示其旧值,直到您调用另一个函数并重复使用该内存。
这是一个很好的设计吗?
当然不是。您依赖于未定义的行为,并且您的代码可能因多种原因而停止工作 - 更改平台或编译器,向代码添加另一个函数调用,或月亮的移动阶段。
我会返回std::wstring
。