在c ++ 11中,是否在函数中返回std :: string移动或复制它?

mmn*_*yle 9 c++ c++11

假设我有以下代码.

std::string foo() {
    std::string mystr("SOMELONGVALUE");
    return mystr;
}

int main() {
    std::string result = foo();
}
Run Code Online (Sandbox Code Playgroud)

当我调用'foo'时,数据是mystr复制还是移入result?我相信它是移动C++ 11风格,但我希望澄清和/或链接来显示.

谢谢!

编辑:我想在使用g ++编译c ++ 11或更高版本时,我想知道这个问题的答案.

sab*_*bee 5

就像 user4581301 所说的,我怀疑在大多数实现中会发生复制省略(不是移动)。对于 c++11 和 c++14,标准允许发生复制省略,但没有强制要求。在 c++17 中,一些复制省略的实例将成为强制性的。因此,对于 c++11 和 c++14,从技术上讲,答案取决于所使用的实现。就您的情况而言,我们正在讨论一种特定类型的复制省略:返回值优化 (RVO)。要检查您的环境中是否发生了给定案例的 RVO,您可以运行以下代码:

#include <iostream>

struct Foo {
  Foo() { std::cout << "Constructed" << std::endl; }

  Foo(const Foo &) { std::cout << "Copy-constructed" << std::endl; }

  Foo(Foo &&) { std::cout << "Move-constructed" << std::endl; }

  ~Foo() { std::cout << "Destructed" << std::endl; }
};

Foo foo() {
    Foo mystr();
    return mystr;
}

int main() {
    Foo result = foo();
}
Run Code Online (Sandbox Code Playgroud)

我的实现选择了 RVO - 没有发生任何变化。


Oli*_*liv 5

您的示例属于所谓的命名返回值优化,它在C ++ 11标准的此段中定义。因此,编译器可能会忽略副本构造函数(或从C ++ 14开始移动构造函数)。此省略不是强制性的。

在C ++ 11中,如果编译器不执行此省略,则返回的字符串将被复制构造。如果返回的对象命名为函数参数[class.copy] / 32(粗体是我的),则该对象将被移动:

当满足或将要执行复制操作的省略标准时,除非源对象是一个函数参数,并且要复制的对象由左值指定,重载分辨率为复制选择了构造函数首先执行,就好像该对象是由右值指定的。[...]

在C ++ 14中,这最后一条规则已更改。它还包括自动变量[class.copy] / 32的情况

当满足复制/移动操作的省略标准,但不满足异常声明的条件,并且要复制的对象由左值指定时,或者当return语句中的表达式为(可能带有括号)id-表达名称带有自动存储持续时间的对象在身体中声明或参数声明子句最内层包围功能或λ-表达,过载的分辨率来选择用于构造的,首先进行复印仿佛对象是由一个rvalue指定。[...]

因此,在您的示例代码中以及在C ++ 14中,如果编译器没有忽略复制/移动构造,则返回的字符串将被移动构造