c++ - 理解 c++11 右值、 move 语义和性能

标签 c++ c++11 move-semantics copy-elision return-value-optimization

<分区>

Possible Duplicate:
What happens if I return literal instead of declared std::string?

考虑以下代码

string getName () {
    return "meme";
}

string name = getName();

getName() 函数返回一个临时对象。在 C++03 中,我理解 string 的复制构造函数被调用并且临时对象被销毁。实际上,编译器(至少在 GCC 4.7 中)似乎通过不创建对象 name 而是将其替换为临时对象本身而不是销毁临时对象来优化第 5 行。 (我尝试使用 MyVector 类,而不是 std::string)

如 C++11 标准中所定义,

  1. getName() 是否返回右值?

  2. 在上面的第 5 行中,调用了字符串的哪个构造函数( move 或复制)?我是否必须调用 std::move() 来调用 move 构造函数?

  3. 使用 move 语义,它的效率是否低于编译器提供的“复制省略”优化?

最佳答案

  1. 函数不返回 右值或左值。值类别适用于表达式。因此,调用 函数的表达式可能是右值或左值。在这种情况下,表达式 getName() 是右值表达式,因为函数 getName 按值返回对象。这来自 §5.2.2/10:

    A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

    您的函数结果类型不是左值或右值引用,因此函数调用是纯右值。纯右值表达式是右值表达式的子集。

  2. 将使用 move 构造函数(除非它被省略,它可能是)。这是因为 getName() 是一个右值,所以采用右值引用的 std::string 的构造函数将更好地匹配参数。请注意,即使 move 构造被省略, move 构造仍然必须是可访问的。也就是说,即使没有省略,代码也必须是可编译的。

  3. 一般来说,复制或 move 省略的优化将完全摆脱任何复制或 move 。所以当然它比实际 move 要快。如果省略了一步,实际上什么也不会发生。该 move 不会发出任何代码。编译器通过直接在对象将被复制或 move 到的位置构造对象来实现这一点。

值得一提的是,这也可以等效优化:

string getName () {
  std::string str("meme");
  return str;
}
 
string name = getName();

此处将省略两步(即通常所说的Named Return Value Optimization)。这里有两点需要考虑。首先,return str; 满足复制/move 省略的标准 (§12.8/31):

This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value
  • ...

其次,虽然 str 是一个左值,但它仍然会被 move ,因为它符合标准 (§12.8/32) 给出的特殊情况:

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

关于c++ - 理解 c++11 右值、 move 语义和性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14012309/

相关文章:

c++ - 在抛出过程中构造对象时抛出异常?

c++ - 从函数返回指针如何工作?

c++ - 如何在 TStringGrid 单元格中绘制按钮

c++ - 具有用户定义的构造函数的普通类型和 POD 类型

c++ - vector 中重复的 unique_ptr 项的所有权错误

c++ - 被信号 11(SIGSEGV) 和/或 6(SIGABRT) 杀死

c++ - QT 将小部件转换到组合框

c++ - 创建与推导参数具有相同类型的局部变量的最简单方法是什么?

templates - 关于 postblit 和 move 语义的问题

c++ - 如何将元素移出 STL 优先级队列