我对返回const
对临时工具的引用的函数声明感到有些困惑。
在以下代码中
#include <string>
#include <iostream>
using namespace std;
const string& foo() {
return string("foo");
}
string bar() {
return string("bar");
}
int main() {
const string& f = foo();
const string& b = bar();
cout << b;
}
方法foo
和bar
之间有什么区别?
为什么foo
会给我warning: returning reference to local temporary object [-Wreturn-stack-address]
。不是const string& f = foo();
上创建的临时副本吗?
答案 0 :(得分:6)
std::string
在函数中创建一个类型为"foo"
的对象,其中包含值main
。该对象将在函数结束时销毁。因此,一旦代码离开该函数[1],返回对该对象的引用将无效。所以在foo
中,你永远不会有对该字符串的有效引用。如果您在string &f = foo()
中创建了一个局部变量,情况也是如此。
返回引用的唯一要点是您不进行复制,初始化引用(main
是初始化)不会创建原始对象的副本 - 只是另一个引用相同的对象[代码返回f
时已经无效]。对于很多东西,引用可以被视为&#34;同一事物的不同名称&#34;。
引用对象的生命周期(换句话说,实际对象&#34;别名和#34;引用)应始终具有比引用变量更长的生命周期(在这种情况下为bar
) 。
在return string("bar");
的情况下,代码将作为{{1}}的一部分进行复制,因为您在没有参考的情况下返回该对象 - 换句话说,通过复制对象,所以这很有效。
[1]迂腐,虽然仍然在函数内部,但是在函数内部编写了代码之后,在编译器引入的代码中处理了函数中创建的对象的破坏。
答案 1 :(得分:0)
在这两种情况下,字符串对象都被初始化并在堆栈上分配。 从函数返回后,包含它的内存段变得无关紧要,并且可以覆盖其内容。
功能之间的区别:
bar
函数返回在其中创建的字符串实例的副本。
foo
函数返回对其中创建的字符串实例的引用。
换句话说,它返回一个指向其返回值的隐式指针,该指针驻留在一个临时内存段中 - 这就是你警告的原因。
答案 2 :(得分:0)
不是
上创建的临时副本const string& f = foo();
你在哪里听到的?
将const
添加到引用通常允许将已初始化的临时值的生命周期延长到引用本身的生命周期。从来没有副本。
尽管如此,情况并非如此。您绑定到引用的对象超出了函数末尾的范围,并且优先于其他所有对象。
您正在返回一个悬空参考;周期。
答案 3 :(得分:0)
为什么foo会给我警告:返回对本地临时的引用 对象[-Wreturn-stack-address]。
您正在foo()
内创建一个临时字符串对象,并且您将返回对该对象的引用,该引用将立即超出范围(悬空引用)。
const string& foo() {
return string("foo"); // returns constant reference to temporary object
} // object goes out of scope
bar()
完全不同:
string bar() {
return string("bar"); // returns a copy of temporary string
}
...
const string& b = bar(); // reference an rvalue string
方法foo和bar有什么区别?
foo()
返回一个常量(悬空)引用,而bar()
返回一个临时字符串对象的副本。