移动语义-这是什么一回事? [英] Move semantics - what it's all about?

查看:221
本文介绍了移动语义-这是什么一回事?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能重复:
有人可以向我解释移动语义吗?

Possible Duplicate:
Can someone please explain move semantics to me?

有人可以为我指出一个好的来源,还是在这里解释一下移动的语义是什么?

Could someone point me to a good source or explain it here what are the move semantics?

推荐答案

暂时忘记C ++ 0x.移动语义是与语言无关的东西-C ++ 0x仅提供了一种使用移动语义执行操作的标准方法.

Forget about C++0x for the moment. Move semantics are something that is language independent -- C++0x merely provides a standard way to perform operations with move semantics.

移动语义定义某些操作的行为.在大多数情况下,它们与复制语义形成对比,因此首先定义它们会很有用.

Move semantics define the behaviour of certain operations. Most of the time they are contrasted with copy semantics, so it would be useful to define them first.

具有复制语义的分配具有以下行为:

Assignment with copy semantics has the following behaviour:

// Copy semantics
assert(b == c);
a = b;
assert(a == b && b == c);

a最终等于b,我们保持b不变.

i.e. a ends up equal to b, and we leave b unchanged.

具有移动语义的分配具有较弱的发布条件:

Assignment with move semantics has weaker post conditions:

// Move semantics
assert(b == c);
move(a, b); // not C++0x
assert(a == c);

请注意,使用移动语义进行赋值后,不再保证b保持不变.这是关键的区别.

Note that there is no longer any guarantee that b remains unchanged after the assignment with move semantics. This is the crucial difference.

移动语义的一个好处是,它允许在某些情况下进行优化.考虑以下常规值类型:

One benefit of move semantics is that it allows optimisations in certain situations. Consider the following regular value type:

struct A { T* x; };

还假设我们将两个A类型的对象定义为相等,前提是它们的x成员指向相同的值.

Assume also that we define two objects of type A to be equal iff their x member point to equal values.

bool operator==(const A& lhs, const A& rhs) { return *lhs.x == *rhs.x; }

最后假设我们定义一个对象A,使其完全拥有其成员x的对象的所有权.

Finally assume that we define an object A to have sole ownership over the pointee of their x member.

A::~A() { delete x; }
A::A(const A& rhs) : x(new T(rhs.x)) {}
A& A::operator=(const A& rhs) { if (this != &rhs) *x = *rhs.x; }

现在假设我们要定义一个函数来交换两个A对象.

Now suppose we want to define a function to swap two A objects.

我们可以使用复制语义以常规方式做到这一点.

We could do it the normal way with copy semantics.

void swap(A& a, A& b)
{
    A t = a;
    a = b;
    b = t;
}

但是,这不必要地效率低下.我们在做什么?

However, this is unnecessarily inefficient. What are we doing?

  • 我们将a的副本创建到t中.
  • 然后我们将b复制到a.
  • 然后将t复制到b.
  • 最后,销毁t.
  • We create a copy of a into t.
  • We then copy b into a.
  • Then copy t into b.
  • Finally, destroy t.

如果T对象的复制成本很高,那么这很浪费.如果我要您交换计算机上的两个文件,则不会创建第三个文件,然后在销毁临时文件之前将文件内容复制并粘贴到周围,对吗?不,您要移动一个文件,将移动第二个文件移到第一个位置,然后最后移动一个文件至第二个文件.无需复制数据.

If T objects are expensive to copy then this is wasteful. If I asked you to swap two files on your computer, you wouldn't create a third file then copy and paste the file contents around before destroying your temporary file, would you? No, you'd move one file away, move the second into the first position, then finally move the first file back into the second. No need to copy data.

在我们的例子中,很容易在A类型的对象周围移动:

In our case, it's easy to move around objects of type A:

// Not C++0x
void move(A& lhs, A& rhs)
{
    lhs.x = rhs.x;
    rhs.x = nullptr;
}

我们只需将rhs的指针移到lhs中,然后放弃该指针的rhs所有权(通过将其设置为null).这应该说明了为什么移动语义的较弱的发布条件可以进行优化.

We simply move rhs's pointer into lhs and then relinquish rhs ownership of that pointer (by setting it to null). This should illuminate why the weaker post condition of move semantics allows optimisations.

定义了新的移动操作后,我们可以定义优化的交换:

With this new move operation defined, we can define an optimised swap:

void swap(A& a, A& b)
{
    A t;
    move(t, a);
    move(a, b);
    move(b, t);
}

移动语义的另一个优点是,它允许您在无法复制的对象之间移动.最好的例子是std::auto_ptr.

Another advantage of move semantics is that it allows you to move around objects that are unable to be copied. A prime example of this is std::auto_ptr.

C ++ 0x允许通过其右值引用功能移动语义.具体来说,这类操作:

C++0x allows move semantics through its rvalue reference feature. Specifically, operations of the kind:

a = b;

b是右值引用(拼写T&&)时,必须具有移动语义,否则它们具有复制语义.当b不是右值引用时,可以使用std::move函数(与我先前定义的move不同)来强制移动语义:

Have move semantics when b is an rvalue reference (spelt T&&), otherwise they have copy semantics. You can force move semantics by using the std::move function (different from the move I defined earlier) when b is not an rvalue reference:

a = std::move(b);

std::move是一个简单的函数,本质上将其参数转换为右值引用.请注意,表达式的结果(例如函数调用)自动是右值引用,因此在这种情况下,您可以利用移动语义,而无需更改代码.

std::move is a simple function that essentially casts its argument to an rvalue reference. Note that the results of expressions (such as a function call) are automatically rvalue references, so you can exploit move semantics in those cases without changing your code.

要定义移动优化,您需要定义一个移动构造函数和一个移动赋值运算符:

To define move optimisations, you need to define a move constructor and move assignment operator:

T::T(T&&);
T& operator=(T&&);

由于这些操作具有移动语义,因此您可以自由修改传入的参数(前提是您将对象置于可破坏的状态).

As these operations have move semantics, you are free to modify the arguments passed in (provided you leave the object in a destructible state).

基本上就是全部.请注意,右值引用还用于允许在C ++ 0x中完美转发(由于右值引用和其他类型之间的特制类型系统交互),但这与移动语义并没有真正的关系,因此我没有讨论在这里.

That's essentially all there is to it. Note that rvalue references are also used to allow perfect forwarding in C++0x (due to the specifically crafted type system interactions between rvalue references and other types), but this isn't really related to move semantics, so I haven't discussed it here.

这篇关于移动语义-这是什么一回事?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆