13.6 Moving Object(移动对象)

使用move的优势:

  • 在一些情况当中,当对象被拷贝后,一个对象立刻被销毁,在这种隐患当中,移动而不是拷贝,对象能够提供一个重大的可执行力增加。
  • 像IO或者unique_ptr类,这些类有资源(像一个指针或者IO缓存)可能不能被分享。因此这种对象不能被拷贝,但是可以移动。

 

库容器,string,和shared_ptr类支持拷贝和移动。

IO和unique_ptr类能够被移动。

 

13.6.1 右值引用

一个右值引用被获取通过&&而不是&

 

通常讲,一个左值表达式涉及一个对象的标识(重命名),而一个右值表达式,涉及一个对象的值。

 

我们不能直接将右值引用绑定到左值

int i = 42;
int &r = i;//ok
int &&rr = i;//error:i为左值,不能将右值引用直接绑定到左值
int &r2 = i * 42;//error:i * 42产生一个const类型的临时变量,左值引用为int型,类型不匹配。
const int &r3 = i * 42;//ok
int &&rr2 = i * 42;//ok

 

返回左值引用的函数:

赋值,下标,解引用和前增前减操作符是全部返回左值的表达式。

返回非引用类型的函数:

算术操作符,关系操作符,按位操作符和后增后减操作符,全部产生右值。

 

左值固定,右值短暂

 

变量是左值

int &&rr1 = 42;//ok,literal is rvalue
int &&rr2 = rr1;//error:rr1 is lvalue

 

变量是左值,我们不能直接将右值引用绑定到左值上,即使那个变量被定义为右值引用类型

 

我们能够销毁一个被移动对象并且能够赋一个新的值给它,但我们不能使用这个被移动对象。

 

Code that uses movw should use std::move, not move.Doing so avoid potential name collisions.

 

13.6.2 移动构造和移动赋值

引用形式的形参在移动构造函数中是右值引用。像在拷贝构造函数,一些额外的形参必须要有默认参数。

StrVec::StrVec(StrVec &&s) noexcept//告知编译器不掷出异常
:elements(s.elements),first_free(s.first_free)
{
    s.elements = s.first_free = s.cap = nullptr;//如果不写这句指针将会被delete
}

 

移动操作符通常不会扔出任何异常

 

移动构造和移动赋值不能扔出任何异常,应该标识为noeccept

 


编译器将会合成转移构造函数,或者转移赋值构造函数,仅当类中没有自己的拷贝控制成员,并且类中的数据成员都能够被移动。

 

和拷贝操作符不同,移动操作符绝对不会隐式定义为删除函数

 

移动操作运算定义为delete 函数的情况:

  • 当类中的成员定义了它自己的复制构造函数,但是没有定义转移构造函数。
  • 类中成员的自己的转移构造函数或者转移复制构造函数操作运算被删除(定义为delete),或者不可访问。
  • 析构函数被删除或者不可访问
  • 类有一个const或者引用类型成员

 

当一个类当中没有转移构造函数,函数机制确保对象能够被拷贝,即使是使用std::move,也将会调用拷贝构造函数。

 

一个转移迭代福适应它的给定迭代器,通过改变迭代器的解引用操作符的行为。

 

在移动和拷贝构造函数的重载当中有一个经典的区别是拷贝构造使用const T&,转移构造使用T&&

 

push_back的重载方式,使用了allocator<T> a

#include <iostream>

using namespace std;

class StrVec {
public:
    void push_back(const string&);
    void push_back(string&&);
};

void StrVec::push_back(const string& s) {
    alloc.construct(first_free++, s);
}

void StrVec::push_back(string&& s) {
    alloc.construct(first_free++, s);
}

 

 

当我们调用push_back时,实参的类型决定我们将新的元素拷贝还是转移到容器当中。

StrVec vec;//empty StrVec
string s = "some string or another";
vec.push_back(s);//call push_back(const string&)
vec.push_back("done");//call push_back(string &&)

 

 

string s1 = "a value", s2 = "another";
auto n = (s1 + s2).find('a');
s1 + s2 = "wow";//向右赋值,s1 + s2得到一个右值?

 

引用限定符可以是 & 或者 &&,指出 this 指向左值还是右值

posted @ 2018-12-03 01:25  Hk_Mayfly  阅读(325)  评论(0)    收藏  举报