包含字符串的类:从函数返回时真正发生的事情?

时间:2018-03-09 17:58:25

标签: c++ c++11 move rvo

并非我不相信我的编译器,但我想知道发生了什么。我们说我有

struct Foo {
  std::string s;
};

我想创建其中一个(在堆栈上),填写非常长的字符串,并从我的函数返回。

Foo f() {
  Foo foo {my_very_long_string};
  return foo;
  // OR: return Foo {my_very_long_string};
}

我知道有像RVO和移动语义这样的东西;我怎么知道他们正在使用它们,并且在运行时它没有在堆上分配一个包含数据的新字符串,复制它并释放旧的字符串? (除了我的程序会变慢。)

是否使用移动构造函数来重用字符串数据?或者它是否使用RVO实际返回相同的字符串?

1 个答案:

答案 0 :(得分:3)

NRVO或移动命名对象

在功能中:

Foo f() {
  Foo foo{my_very_long_string};
  return foo;
}

对象foo有一个名称(即:foo),它是名为的对象。

可以发生

命名RVO (NRVO),这是一种可选的优化。如果没有发生NRVO,则移动foo,因为它是一个本地对象,因此在此上下文中被视为右值(即:return语句)。

RVO / copy elsion或move for unnamed objects

但是,在功能中:

Foo f() {
  return Foo{my_very_long_string};
}

未命名的对象,是由Foo{my_very_long_string}产生的对象。

  • 从C ++ 17开始,副本必须省略(即:与RVO相同,但语义不同)。

  • 在C ++ 17之前,可能会出现RVO,这是可选的优化。如果没有,则移动它,因为Foo{my_very_long_string}已经是右值。

在上述任何情况下都不会为新字符串分配堆。