为什么此代码可以在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;
}
答案 0 :(得分:2)
离开函数后,所有局部变量都将被销毁。通过返回对tmp
的引用,您将返回对很快就不存在的对象的引用(即,技术上,内容不再有意义的内存区域的地址)。
访问这样一个悬空引用会调用所谓的“未定义行为” - 遗憾的是,“照常工作”是一种“未定义的行为”。这里可能发生的是std::string
为小字符串保留一个小的静态缓冲区(而不是从字符串中抓取内存的大字符串),并且在离开getString
时由此占用的堆栈空间字符串不归零所以它似乎仍然有效。
如果您尝试调试构建,或者在其间调用另一个函数(这将有效地覆盖堆栈空间),它将不再起作用。
答案 1 :(得分:1)
您正在导致未定义的行为。该标准没有说明在这种情况下会发生什么,但是编译器检测到它。
答案 2 :(得分:1)
tmp
返回时, getString
消失。使用返回的引用是未定义的行为,因此任何事情都可能发生。
要修复代码,请按值返回字符串:
string getString(const string &s)
{
...
答案 3 :(得分:1)
也许this link会帮助你。
答案 4 :(得分:0)
你的字符串是通过引用返回的,也就是说,不是在你要返回的上下文中创建一个有效的新字符串,而是返回一个指向陈旧的,被破坏的对象的指针,这很糟糕。 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;
}