在函数范围内声明的C ++返回引用

时间:2012-09-05 07:01:35

标签: c++ function

  

可能重复:
  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]可能无效。 但似乎工作正常,它是如何工作的? 这是一个很好的设计吗? 感谢。

4 个答案:

答案 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