为什么在这个例子中可以返回临时对象?
Why the temporary object can be returned in this example?
char*[]
对象可以通过 const 引用传递给函数 version2() 和 version3(),这意味着 s2 是一个等于“###”或“@@@”的临时对象。
但是为什么临时对象 s2可以返回,而临时对象temp 不能。
int main()
{
result = version2(input, "###");
cout << "Your string enhanced: " << result << endl;
result = version3(input, "@@@");
cout << "Your string enhanced: " << result << endl;
return 0;
}
// No Error
const string & version2(string & s1, const string & s2)
{
return s2;
}
// Error
const string & version3(string & s1, const string & s2)
{
string temp = s2 + s1 + s2;
return temp;
}
两个版本return 对对象的引用。
version2
从 main 获得了一个引用并且 return 它没有被修改回来。
version3
定义了一个局部变量temp
并且想return引用这个局部。但不幸的是,当您从 version3
编辑 return 后,本地就不再存在了。因此,您将 return 一个已经被销毁的引用。
重点是object life time.
对于第一种情况,如您所说,创建一个临时 std::string
并传递给 version2
(绑定到参数 s2
)。 full-expression后,即整个result = version2(input, "###");
后,临时会被销毁。这意味着由 version2
编辑的引用 return 仍然有效,可以将其用于分配给 result
.
All temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created,
对于第二种情况,在version3
中创建了一个本地对象temp
,在退出version3
时销毁。这意味着 version3
将始终是 return 悬空引用。并使用它分配给 result
导致 UB。编译器可能会给出诊断;但不必做。
我会这么说只是因为编译器认为 version2
不危险。
请注意,对于 version3
,它实际上给出了警告,而不是错误(除非您告诉它)。
其实如果改成catch result by reference,还是不会有warning的,但是temporary肯定已经被破坏了。您可以检查程序集(或标准),但在这里我重现它并使其易于观察。 (尽管这取决于编译器)
如果您切换优化,您可以看到输出变化并且不会发出任何警告。
为了以防万一,这里是测试代码
#include<string>
#include<iostream>
using namespace std;
// No Error
auto& f(const string & s){return s;}
int main()
{
char s[]="#";
const char* cs = s;
auto& x = f(cs);
s[0]='o';
[[maybe_unused]] auto& y = f(cs);
cout << x;
}
g++7.2 -Wall -Wextra -std=c++17
char*[]
对象可以通过 const 引用传递给函数 version2() 和 version3(),这意味着 s2 是一个等于“###”或“@@@”的临时对象。
但是为什么临时对象 s2可以返回,而临时对象temp 不能。
int main()
{
result = version2(input, "###");
cout << "Your string enhanced: " << result << endl;
result = version3(input, "@@@");
cout << "Your string enhanced: " << result << endl;
return 0;
}
// No Error
const string & version2(string & s1, const string & s2)
{
return s2;
}
// Error
const string & version3(string & s1, const string & s2)
{
string temp = s2 + s1 + s2;
return temp;
}
两个版本return 对对象的引用。
version2
从 main 获得了一个引用并且 return 它没有被修改回来。
version3
定义了一个局部变量temp
并且想return引用这个局部。但不幸的是,当您从 version3
编辑 return 后,本地就不再存在了。因此,您将 return 一个已经被销毁的引用。
重点是object life time.
对于第一种情况,如您所说,创建一个临时 std::string
并传递给 version2
(绑定到参数 s2
)。 full-expression后,即整个result = version2(input, "###");
后,临时会被销毁。这意味着由 version2
编辑的引用 return 仍然有效,可以将其用于分配给 result
.
All temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created,
对于第二种情况,在version3
中创建了一个本地对象temp
,在退出version3
时销毁。这意味着 version3
将始终是 return 悬空引用。并使用它分配给 result
导致 UB。编译器可能会给出诊断;但不必做。
我会这么说只是因为编译器认为 version2
不危险。
请注意,对于 version3
,它实际上给出了警告,而不是错误(除非您告诉它)。
其实如果改成catch result by reference,还是不会有warning的,但是temporary肯定已经被破坏了。您可以检查程序集(或标准),但在这里我重现它并使其易于观察。 (尽管这取决于编译器)
如果您切换优化,您可以看到输出变化并且不会发出任何警告。
为了以防万一,这里是测试代码
#include<string>
#include<iostream>
using namespace std;
// No Error
auto& f(const string & s){return s;}
int main()
{
char s[]="#";
const char* cs = s;
auto& x = f(cs);
s[0]='o';
[[maybe_unused]] auto& y = f(cs);
cout << x;
}
g++7.2 -Wall -Wextra -std=c++17