并非我不相信我的编译器,但我想知道发生了什么。我们说我有
struct Foo {
std::string s;
};
我想创建其中一个(在堆栈上),填写非常长的字符串,并从我的函数返回。
Foo f() {
Foo foo {my_very_long_string};
return foo;
// OR: return Foo {my_very_long_string};
}
我知道有像RVO和移动语义这样的东西;我怎么知道他们正在使用它们,并且在运行时它没有在堆上分配一个包含数据的新字符串,复制它并释放旧的字符串? (除了我的程序会变慢。)
是否使用移动构造函数来重用字符串数据?或者它是否使用RVO实际返回相同的字符串?
答案 0 :(得分:3)
在功能中:
Foo f() {
Foo foo{my_very_long_string};
return foo;
}
对象foo
有一个名称(即:foo
),它是名为的对象。
命名RVO (NRVO),这是一种可选的优化。如果没有发生NRVO,则移动foo
,因为它是一个本地对象,因此在此上下文中被视为右值(即:return
语句)。
但是,在功能中:
Foo f() {
return Foo{my_very_long_string};
}
未命名的对象,是由Foo{my_very_long_string}
产生的对象。
从C ++ 17开始,副本必须省略(即:与RVO相同,但语义不同)。
在C ++ 17之前,可能会出现RVO,这是可选的优化。如果没有,则移动它,因为Foo{my_very_long_string}
已经是右值。
在上述任何情况下都不会为新字符串分配堆。