【问题标题】:Returning std::move of a local variable [duplicate]返回局部变量的 std::move [重复]
【发布时间】:2013-08-16 04:24:51
【问题描述】:

让一个类A 带有一个移动构造函数。考虑一下:

A get()
{
    A a;
    return std::move( a );
}

// later in the code
A aa = get();

这里对std:move 的显式调用强制调用A 的移动构造函数,因此它可能会在调用get() 时抑制返回值优化。因此,据说get() 的更好实现是这样的:

A get()
{
    A a;
    return a;
}

但是返回值优化不是 C++11 标准的一部分,所以WHAT IF编译器出于某种原因决定在调用get() 时不执行返回值优化。在这种情况下,A 的复制构造函数将在返回 get() 时被调用,对吗?

那么get() 的第一个实现不是更受欢迎吗??

【问题讨论】:

  • 如果你的编译器决定在每个函数调用之前插入一百万个 nop 怎么办?您必须选择您的工具...而且 RVO 标准的明确部分,它不是强制性
  • 不需要std::move。如果可访问,A 的移动构造函数将被 12.8/32 调用。
  • @Vahagn 是的。这是一个两阶段的过载解决方案。首先,返回的对象被视为右值。如果在这种情况下重载决议失败,则将其视为左值。这里的重点是,返回的对象的类型与你的函数的返回类型相同......
  • 如果你返回一个A类型的对象,但函数的返回类型是B,而B有一个(移动)构造函数以A作为参数,那么如果你想移动语义,你必须明确写move
  • 再补充一点:如果移动构造函数是私有的或被删除的,那么无论拷贝构造函数是公共的还是私有的,代码都不会编译。

标签: c++ c++11 move-semantics return-value-optimization


【解决方案1】:

编译器应该使用移动构造函数,但我没有看到标准中的义务: 在有关临时对象的部分中总是说“复制/移动构造函数”

标准 ISO/IEC 14882:2011 C++:

"

12.1/9

复制构造函数 (12.8) 用于复制类类型的对象。移动构造函数(12.8)用于移动 类类型对象的内容。

12.8/32

当满足或将满足省略复制操作的条件时,除了源 object 是函数参数,要复制的对象由 lvalue 指定,重载决议为 选择副本的构造函数首先执行,就好像对象是由 rvalue 指定的一样。如果过载 解析失败,或者如果所选构造函数的第一个参数的类型不是 rvalue 引用 对象的类型(可能是 cv 限定的),再次执行重载决议,将对象视为 左值。 [注意:无论复制省略是否会执行,都必须执行此两阶段重载解析 发生。它确定如果不执行省略则要调用的构造函数,以及选择的构造函数 即使调用被省略,也必须是可访问的。 ——尾注]

"

左值 = T &
右值 = T &&

所以,它说首先,编译器会查找是否找到移动构造函数,然后会查找移动构造函数。

因此,如果您的编译器符合标准,它将调用移动构造函数。

我只添加有趣的内容:

"
12.8/31 当满足某些标准时,允许实现省略类的复制/移动构造 对象,即使对象的复制/移动构造函数和/或析构函数有副作用。
"

...所以即使这些构造函数/析构函数有副作用,也可以跳过

【讨论】:

  • 如果 12.8/32 可以访问,符合标准的实现必须使用移动构造函数!
  • 我的母语不是英语,所以“复制操作的省略”意味着“移动操作”?
  • “复制省略”在 12.8/31 中定义。这包括省略复制构造函数和移动构造函数。
  • 好的,我编辑了,我现在明白了:)谢谢
猜你喜欢
  • 1970-01-01
  • 2016-01-19
  • 2021-04-28
  • 1970-01-01
  • 2015-08-11
  • 1970-01-01
  • 1970-01-01
  • 2017-10-19
相关资源
最近更新 更多