本文为第二部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/4220233.html。
Move语义
假设x是一个类,其含有一个指针或者某些资源的句柄(handle)。写作m_pResource
。由这个资源,我的意思是包括构造、克隆、析构都认真考虑在内的,一个绝佳的例子是std::vector。它可以在一个分配的内存数组中包含一个对象集合。接下来,从逻辑上,对于x的拷贝赋值操作符一般如下:
X& X::operator=(X const & rhs) { // [...] // 析构 m_pResource指向的资源. // 对rhs.m_pResource所指向的资源做一份克隆,然后 // 再把它附在 m_pResource上. // [...] }
因为类似的原因这也适用于拷贝构造函数。现在假设x被如下使用:
X foo(); X x; // x也许被通过多种方式使用 x = foo();
在最后一行执行前:
- 析构了被x持有的资源
- 克隆了从foo返回的临时变量
- 析构了那个临时变量并从而释放了它指向的资源
显而易见的,这样是可行的,但还有一种更有效率的做法,那就是交换(swap)x和临时变量中的对资源的指针或者句柄(handles),然后让临时变量的析构器析构原来x的资源。换一种说法,在这种特别的情况下,位于赋值右手边的是右值。我们希望拷贝构造函数如下表现:
// [...] // 交换m_pResource和rhs.m_pResource // [...]
这被称作Move语义。在C++11中,这种条件性的行为可以通过如下重载来实现:
X& X::operator=(<mystery type> rhs) { // [...] // 交换this->m_pResource和rhs.m_pResource // [...] }
因为我们定义了一个对于拷贝构造函数的重载,我们的「mystery type」必须本质上是一个引用:我们当然想让右手边的值可以通过引用传递给我们。而且,我们期望mystery type有如下的行为:当面临到原始的引用类型和mystery type的重载选择时,右值一定优先选择mystery type的重载,而左值一定优先选择原始的引用类型。
如果你现在意识到在上文中「右值引用」就是指代「mystery type」的话,那么你已经从本质上看到了右值引用的定义。