sma*_*llB 10 c++ rvalue-reference move-semantics c++11
可能重复:
有人可以向我解释移动语义吗?
有人能指出一个好的来源或在这里解释什么是移动语义?
Pet*_*der 34
暂时忘掉C++ 0x.移动语义是与语言无关的东西--C++ 0x仅提供了一种使用移动语义执行操作的标准方法.
移动语义定义了某些操作的行为.大多数情况下,它们与复制语义形成对比,因此首先定义它们会很有用.
具有复制语义的赋值具有以下行为:
// Copy semantics
assert(b == c);
a = b;
assert(a == b && b == c);
Run Code Online (Sandbox Code Playgroud)
即a
结束等于b
,我们b
保持不变.
具有移动语义的赋值具有较弱的后置条件:
// Move semantics
assert(b == c);
move(a, b); // not C++0x
assert(a == c);
Run Code Online (Sandbox Code Playgroud)
请注意,在b
使用移动语义分配后,不再保证保持不变.这是至关重要的区别.
移动语义的一个好处是它允许在某些情况下进行优化.请考虑以下常规值类型:
struct A { T* x; };
Run Code Online (Sandbox Code Playgroud)
假设我们将两个类型的对象定义A
为相等,如果它们的x
成员指向相等的值.
bool operator==(const A& lhs, const A& rhs) { return *lhs.x == *rhs.x; }
Run Code Online (Sandbox Code Playgroud)
最后假设我们定义一个对象A
,对其x
成员的指针拥有唯一的所有权.
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; }
Run Code Online (Sandbox Code Playgroud)
现在假设我们要定义一个交换两个A
对象的函数.
我们可以通过复制语义以正常方式完成它.
void swap(A& a, A& b)
{
A t = a;
a = b;
b = t;
}
Run Code Online (Sandbox Code Playgroud)
然而,这是不必要的低效率.我们在做什么?
a
into 的副本t
.b
到a
.t
到b
.t
.如果T
复制对象很昂贵,那么这很浪费.如果我要求您在计算机上交换两个文件,则不会创建第三个文件,然后在销毁临时文件之前复制并粘贴文件内容,是吗?不,你移动一个文件,将第二个文件移动到第一个位置,然后最后将第一个文件移回第二个文件.无需复制数据.
在我们的例子中,很容易移动类型的对象A
:
// Not C++0x
void move(A& lhs, A& rhs)
{
lhs.x = rhs.x;
rhs.x = nullptr;
}
Run Code Online (Sandbox Code Playgroud)
我们只需将rhs
指针移入lhs
然后放弃rhs
该指针的所有权(通过将其设置为null).这应该说明为什么移动语义的较弱的后置条件允许优化.
通过定义这个新的移动操作,我们可以定义优化的交换:
void swap(A& a, A& b)
{
A t;
move(t, a);
move(a, b);
move(b, t);
}
Run Code Online (Sandbox Code Playgroud)
移动语义的另一个优点是它允许您移动无法复制的对象.一个很好的例子是std::auto_ptr
.
C++ 0x允许通过其右值引用功能移动语义.具体来说,这种操作:
a = b;
Run Code Online (Sandbox Code Playgroud)
在b
rvalue引用(拼写T&&
)时移动语义,否则它们具有复制语义.当不是右值引用时,可以使用std::move
函数(与move
前面定义的不同)强制移动语义b
:
a = std::move(b);
Run Code Online (Sandbox Code Playgroud)
std::move
是一个简单的函数,它基本上将其参数强制转换为右值引用.请注意,表达式的结果(例如函数调用)是自动右值引用,因此您可以在不更改代码的情况下利用移动语义.
要定义移动优化,您需要定义移动构造函数并移动赋值运算符:
T::T(T&&);
T& operator=(T&&);
Run Code Online (Sandbox Code Playgroud)
由于这些操作具有移动语义,因此您可以自由修改传入的参数(假设您将对象置于可破坏状态).
这基本上就是它的全部内容.注意,右值引用也用于允许在C++ 0x中完美转发(由于rvalue引用和其他类型之间特别设计的类型系统交互),但这与移动语义无关,所以我没有讨论过在这里.
归档时间: |
|
查看次数: |
5942 次 |
最近记录: |