返回对局部变量的引用

时间:2011-09-21 12:38:42

标签: c++ reference compiler-warnings local-variables

为什么此代码可以在Code :: block中成功运行。 IDB刚报告

  

警告:“引用局部变量'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 个答案:

答案 0 :(得分:2)

离开函数后,所有局部变量都将被销毁。通过返回对tmp的引用,您将返回对很快就不存在的对象的引用(即,技术上,内容不再有意义的内存区域的地址)。

访问这样一个悬空引用会调用所谓的“未定义行为” - 遗憾的是,“照常工作”是一种“未定义的行为”。这里可能发生的是std::string为小字符串保留一个小的静态缓冲区(而不是从字符串中抓取内存的大字符串),并且在离开getString时由此占用的堆栈空间字符串不归零所以它似乎仍然有效。

如果您尝试调试构建,或者在其间调用另一个函数(这将有效地覆盖堆栈空间),它将不再起作用。

答案 1 :(得分:1)

您正在导致未定义的行为。该标准没有说明在这种情况下会发生什么,但是编译器检测到它。

答案 2 :(得分:1)

tmp返回时,

getString消失。使用返回的引用是未定义的行为,因此任何事情都可能发生。

要修复代码,请按值返回字符串:

string getString(const string &s)
{
...

答案 3 :(得分:1)

也许this link会帮助你。

答案 4 :(得分:0)

你确定吗?它应该是段错误的(它将在大多数平台上使用gcc)。该代码确实包含错误,如果你“幸运”并且它有效,那么你就会在地毯下刷一个讨厌的虫子。

你的字符串是通过引用返回的,也就是说,不是在你要返回的上下文中创建一个有效的新字符串,而是返回一个指向陈旧的,被破坏的对象的指针,这很糟糕。 const string getString...将作为函数返回类型的声明。

答案 5 :(得分:0)

临时对象被释放,但其内容仍然存在于堆栈中,直到重写它为止。尝试在调用函数和打印返回的对象之间调用一些函数:

const string& garbage = getString("Hello World!");
callSomeFunctionThatUsesALotOfStackMemory();
cout<< garbage << endl;

答案 6 :(得分:0)

C ++标准告诉我们将临时对象绑定到const引用会将临时对象的生命周期延长到引用本身的生命周期。 所以代码应该适用于任何符合标准的编译器,但是在我看来,实践本身并不是很好。

如果您确实在示例中使用了当前未使用的字符串作为字符串a = getString(“Hello World!”),您只需复制一个字符串&amp; a = getString(“Hello World!”)我打赌你永远不应该让你的临时服用。

答案 7 :(得分:0)

正如您所看到的,通过调用goodByeString()稍微修改了下面的示例代码。就像已经指出的其他答案一样,getString中名为tmp的变量是local。一旦函数返回,变量就会超出范围。因为它是堆栈分配的,当函数返回时内存仍然有效,但是一旦堆栈再次增长,tmp所在的这部分内存将被其他东西重写。然后对a的引用包含垃圾。

但是,如果您决定输出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;
}