有一天,我想知道返回字符串对象时是否有内存副本。但是,我觉得很奇怪。当我在函数中返回一个对象时,我希望有一个复制结构来创建一个临时对象作为返回值。所以,我尝试以下代码。
class Substring: public string
{
public:
Substring(const char* s)
:string(s)
{
}
~Substring()
{
cout << "Deconstruct" << endl;
}
};
Substring foo()
{
Substring ret("test");
printf("Inner address: %p\n", ret.c_str());
return ret;
}
int main()
{
Substring test = foo();
printf("Return address: %p\n", test.c_str());
return 0;
}
正如我所说,我期待Return address
与Inner address
不同。并且Deconstruct
应该在Inner address
这就是我得到的。当外部变量ret
死亡时,似乎解构test
,而不是超出其范围的时间!为什么呢?
Inner address: 0x7ffed3a4cb40
Return address: 0x7ffed3a4cb40
Deconstruct
答案 0 :(得分:1)
C ++有这个叫做elision的东西。
多个对象可以将它们的生命时间省略在一起。这意味着乍一看有3个子串对象(ret
,test
和匿名返回值),在省略后,它们都是同一个对象,只有一个构造和破坏。
对于elision有各种限制(标准强制和实用),并且c++17某些形式被强制执行。
特别是,几乎总是允许删除prvalue,如果在C ++ 17中几乎总是允许的话。
如果return语句为return var_name;
并且类型匹配,则可以使用prvalues省略命名变量,并使用命名的locals返回值。
人们为特定种类的精灵 - RVO和NRVO - 制作了名称 - 但我觉得它们比启发更令人困惑。
禁用elision是一个坏主意,必须这样做表明你的对象模型与C ++的假设不同。