当未明确使用std :: move时,c ++ 11何时会自动执行?

时间:2014-08-06 07:26:16

标签: c++ c++11 move-semantics rvalue-reference lvalue

如果我有一个struct我没有提供任何副本并移动构造函数:

struct MyStruct {
  MyStruct() { // this is the only function
    ...
  }
  ...
};

然后如果我执行以下操作:

std::vector<MyStruct> vec;
...
vec.push_back(MyStruct());

而不是使用std::move(),如下所示:

vec.push_back(std::move(MyStruct()));

c ++ 11会巧妙地为我的临时变量做些什么吗?或者,我怎样才能确定它是移动而不是副本?

5 个答案:

答案 0 :(得分:10)

在C ++ 11中std::vector::push_back如果传递rvalue将使用移动构造函数(并且该类型存在移动构造函数),但在这种情况下也应考虑使用std::vector::emplace_back; std::vector::emplace_back将构建对象而不是移动它。

答案 1 :(得分:7)

  

c ++ 11会巧妙地为我的临时变量做些什么吗?或者,我怎样才能确定它是移动而不是副本?

这取决于。此

vec.push_back(MyStruct());

将绑定到

std::vector<MyStruct>::push_back(MyStruct&&);

但是移动或复制的rvalue是否完全取决于MyStruct是否具有移动复制构造函数(同样用于移动分配)。

如果你打电话

,那绝对没有区别
vec.push_back(std::move(MyStruct()));

因为MyStruct()已经是左值。

所以它真的取决于MyStruct的细节。你的问题中没有足够的信息来知道你的班级是否有移动构造函数。

这些是类具有隐式生成的移动构造函数必须满足的条件:

  • 没有用户声明的副本构造函数
  • 没有用户声明的副本分配运算符
  • 没有用户声明的移动分配操作符
  • 没有用户声明的析构函数

当然,如果不满足以下任何条件,您可以随时提供:

MyStruct(MyStruct&&) = default;

答案 2 :(得分:4)

因为MyStruct()会创建一个左值,所以会调用T &&重载。

实际上很容易验证(demo):

#include <iostream>
struct A{ int x; };

void  foo(A &&x){ std::cout<<"&&" <<std::endl; }

void  foo(A &x){ std::cout<<"&" <<std::endl; }

int main() {
    foo(A()); // prints &&
    A a;
    foo(a); // prints &
    return 0;
}

澄清一下:我没有提及有关移动构造函数的任何内容,因为可以有一个显式删除的移动构造函数,但仍会调用T &&

E.g(demo):

#include <iostream>
struct A{ int x; A() = default; A(const A& ) = default; A(A&&) = delete; };
/*                                                                  ^
                                                            no move ctor */
void  foo(A &&x){ std::cout<<"&&" <<std::endl; }

void  foo(A &x){ std::cout<<"&" <<std::endl; }

int main() {
    foo(A()); //still prints &&
    A a;
    foo(a);
    return 0;
}

正如我之前所说,这是因为它是一个左值......

答案 3 :(得分:1)

是的,它将使用push_back( T&& value ),并移动值。

答案 4 :(得分:1)

如果类型是可移动的,那肯定会是。通常,符合标准的编译器应始终选择移动语义来复制语义(如果有的话)。