Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 移动语义-它是什么';什么事?_C++_C++11_Rvalue Reference_Move Semantics - Fatal编程技术网

C++ 移动语义-它是什么';什么事?

C++ 移动语义-它是什么';什么事?,c++,c++11,rvalue-reference,move-semantics,C++,C++11,Rvalue Reference,Move Semantics,可能重复: 有人能给我指出一个好的来源,或者在这里解释一下什么是移动语义吗?基本上,右值引用允许您检测对象何时是临时对象,您不必保留它们的内部状态。这使得C++03以前必须一直复制的代码更加高效,在C++0x中,您可以继续重复使用相同的资源。此外,右值引用可以实现完美的转发 看看。暂时忘掉C++0x。移动语义是与语言无关的——C++0x仅提供了使用移动语义执行操作的标准方法 void swap(A& a, A& b) { A t = a; a = b;

可能重复:


有人能给我指出一个好的来源,或者在这里解释一下什么是移动语义吗?

基本上,右值引用允许您检测对象何时是临时对象,您不必保留它们的内部状态。这使得C++03以前必须一直复制的代码更加高效,在C++0x中,您可以继续重复使用相同的资源。此外,右值引用可以实现完美的转发


看看。

暂时忘掉C++0x。移动语义是与语言无关的——C++0x仅提供了使用移动语义执行操作的标准方法

void swap(A& a, A& b)
{
    A t = a;
    a = b;
    b = t;
}
定义 移动语义定义了某些操作的行为。大多数情况下,它们与复制语义形成对比,因此首先定义它们是有用的

具有复制语义的赋值具有以下行为:

// Copy semantics
assert(b == c);
a = b;
assert(a == b && b == c);
i、 e.
a
最终等于
b
,我们保持
b
不变

移动语义为的赋值具有较弱的后置条件:

// Move semantics
assert(b == c);
move(a, b); // not C++0x
assert(a == c);
请注意,不再保证
b
在使用移动语义赋值后保持不变。这是关键的区别

使用 移动语义的一个好处是,它允许在某些情况下进行优化。考虑下面的正则值类型:

struct A { T* x; };
还假设我们将两个
A
类型的对象定义为相等,前提是它们的
x
成员点的值相等

bool operator==(const A& lhs, const A& rhs) { return *lhs.x == *rhs.x; }
最后假设我们定义了一个对象
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; }
现在假设我们想要定义一个函数来交换两个
a
对象

我们可以用复制语义的正常方式来做

void swap(A& a, A& b)
{
    A t = a;
    a = b;
    b = t;
}
然而,这是不必要的低效。我们在干什么

  • 我们将
    a
    的副本创建到
    t
  • 然后我们将
    b
    复制到
    a
  • 然后将
    t
    复制到
    b
  • 最后,销毁
    t
如果
T
对象的复制成本很高,那么这是浪费。如果我让你交换计算机上的两个文件,你不会创建第三个文件,然后在销毁临时文件之前复制并粘贴文件内容,是吗?不,您将移动一个文件,将第二个文件移到第一个位置,然后最后将第一个文件移回第二个位置。无需复制数据

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

// Not C++0x
void move(A& lhs, A& rhs)
{
    lhs.x = rhs.x;
    rhs.x = nullptr;
}
我们只需将
rhs
的指针移动到
lhs
中,然后放弃该指针的所有权(通过将其设置为null)。这应该说明为什么移动语义较弱的post条件允许优化

通过定义此新移动操作,我们可以定义优化交换:

void swap(A& a, A& b)
{
    A t;
    move(t, a);
    move(a, b);
    move(b, t);
}
移动语义的另一个优点是,它允许您在无法复制的对象周围移动。这方面的一个主要例子是
std::auto_ptr

C++0x C++0x通过其右值引用特性允许移动语义。具体而言,此类操作:

a = b;
如果
b
是右值引用(拼写
T&
),则具有移动语义,否则具有复制语义。当
b
不是右值引用时,可以使用
std::move
函数强制移动语义(不同于前面定义的
move
I):

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

要定义移动优化,您需要定义移动构造函数和移动分配运算符:

T::T(T&&);
T& operator=(T&&);
由于这些操作具有移动语义,因此可以自由修改传入的参数(前提是将对象保持在可破坏状态)

结论
这基本上就是它的全部。请注意,在C++0x中,rvalue引用还用于允许完美转发(由于rvalue引用和其他类型之间专门构建的类型系统交互),但这与移动语义并没有真正的关系,所以我没有在这里讨论它。

大约一年来,我阅读了大量的文本解释,直到我看了Scott Meyer的精彩演讲,才掌握了r值参考的所有内容:

他解释的方式很有趣,速度也很慢,足以理解过程中发生的每一件事

我知道,这是1h30,但实际上,这是我去年得到的最好的解释


在阅读了这些文章(和其他答案一样)之后,观看这段视频确实以一种一致的方式在我的脑海中融为一体,几天后,我能够向一些同事解释它,并解释如何使用std::unique_ptr(因为它是相关的-它只允许移动语义,而不允许复制),因为它需要理解std::move(),这需要理解移动语义。

很高兴看到这样的问题,我也很高兴与大家分享我的观点。我想你是在询问C++语言本身的错误修复,而不仅仅是C++语言的特性。“臭虫”已经存在了几十年了。也就是说,复制构造函数

void swap(A& a, A& b)
{
    A t = a;
    a = b;
    b = t;
}
如果你知道在物理学中有很多东西是不能复制的,比如能量和质量,那么复制构造函数看起来很奇怪。这只是一个玩笑,但实际上在编程世界中,像独占文件描述符这样的对象是不可复制的。所以C++程序员和设计师发明了一些技巧来解决这个问题。有三种著名的:NRVO、
boost::noncopyable
std::auto\u ptr

NRVO(命名返回值优化)i