Chapter3 Move Semantics in Classes

1. Move Semantics in Ordinary Classes

①C++11之后,编译器会为简单的类生成 移动构造函数 和 移动赋值运算符
(就像生成的默认构造函数和默认赋值运算符)
什么时候会使用移动构造

  1. 当返回一个局部变量(return local obj by value)
  2. 按值传递一个无名对象
  3. 传递一个临时对象(例如 函数的返回值)
  4. 被std::move 标记的对象

③测试代码

一个简单的类 只有构造函数和一个重载的运算符

class Test
{
public:
     Test(const std::string& Temp) : str{Temp} {};
     

     friend ostream& operator<<(ostream& os, const Test& Temp)
     {
          os << Temp.str << endl;
          return os;
     }

private:
     std::string str;
};
int main()
{
     Test a("12345678910111213");
     cout <<"a   " << a << endl;

     cout << "***************" << endl;

     Test b = a;
     cout << "a   " << a << endl;
     cout << "b   " << b << endl;

     cout << "***************" << endl;

     Test c = std::move(a);
     cout << "a   " << a << endl;
     cout << "b   " << b << endl;
     cout << "c   " << c << endl;


     return 0;
}

在这里插入图片描述
我们可以看到 a的值已经被move给了c了

Test d = {std::move(b)};
     cout << "a   " << a << endl;
     cout << "b   " << b << endl;
     cout << "c   " << c << endl;
     cout << "d   " << d << endl;

我们可以看到 大括号初始化和赋值初始化中使用std::move确实被移动了

2.什么时候编译器不会自动生成这两个函数呢?

编译器得保证它自动生成的函数是正确的,符合用户需求的,所以编译器会受到一些限制。

①当类中有拷贝构造函数的时候
我们以前知道,对一个对象使用std::move,当该类中的构造函数没有存在右值引用的形参的时候X&&,他便会去找形参是const X&的构造函数
②当类中有拷贝赋值运算符
③其他的移动操作
④析构函数
基类有个虚的析构函数,但是子类没有析构函数,子类会生成这两个函数

/*****************************************************/
当发生上面情况的时候,那么编译器不会为我们生成移动函数了,所以我们需要注意
①可能会调用拷贝函数,得到的是我们不期望的结果
比如直接拷贝指针 进行了浅拷贝
②类的成员对值有要求
③对象没有默认的构造状态

3.Implementing Special Copy/Move Member Functions

// move constructor (move all members):
Customer(Customer&& cust)
: name{std::move(cust.name)}, values{std::move(cust.values)} 
{
	std::cout << "MOVE " << name << \n;
}
// move assignment (move all members):
Customer& operator= (Customer&& cust) 
{
	std::cout << "MOVEASSIGN " << cust.name << \n;
	if (this != &cust) 
	{ // move assignment to itself?
		name = std::move(cust.name);
		values = std::move(cust.values);
	}
	return *this; 
}

4. Rules for Special Member Functions

在这里插入图片描述
① 如果用户没有自定义构造函数,那么就会有默认构造函数
②拷贝成员函数 和析构函数 会禁止生成默认的移动成员函数
③move成员函数 会禁止生成默认的 copy成员函数

Deleting Moving Makes No Sense

class Person {
public:
...
// NO copy constructor declared
// move constructor/assignment declared as deleted:
Person(Person&&) = delete;
Person& operator=(Person&&) = delete;
...
};

你禁用了move,但是当类中声明了move成员函数,copy成员函数也被禁用了!

Person p{"Tina", "Fox"};
coll.push_back(p); // ERROR: copying disabled
coll.push_back(std::move(p)); // ERROR: moving disabled

/***************************************************/
Disabling Move Semantics

class Customer {
...
public:
...
Customer(Customer&&) = delete; // OOPS: does disable move calls
Customer& operator=(Customer&&) = delete; // OOPS: does disable move calls
};

这虽然是可以禁止移动语意,但是通常不是合适的做法

class Customer {
...
public:
...
Customer(const Customer&) = default; // disable move semantics
Customer& operator=(const Customer&) = default; // disable move semantics
};

上面是通常的做法
/***********************************************************/
Moving for Members with Disabled Move Semantics

class Customer {
...
public:
...
Customer(const Customer&) = default; // copying calls enabled
Customer& operator=(const Customer&) = default; // copying calls enabled
Customer(Customer&&) = delete; // moving calls disabled
Customer& operator=(Customer&&) = delete; // moving calls disabled
};
class Invoice
 {
std::string id;
Customer cust;
public:
... // no special member functions
};
Invoice i;
Invoice i1{std::move(i)}; // OK, moves id, copies cust

默认生成的拷贝函数和移动函数,会根据成员是否能移动或能拷贝做出不同的行为

5.Exact Rules for Generated Special Member Functions

我们有如下的派生类

class MyClass : public Base
{
private:
MyType value;
...
};

/************************************************/
Copy Constructor
拷贝构造函数自动生成的条件,是在没有用户没有自定义移动构造函数
和 移动赋值运算符的时候

通常像下面这样,基类的构造函数总是先执行

MyClass(const MyClass& obj)
: Base{obj}, value{obj.value}
{

}

/**********************************************/
Move Constructor
move构造函数 自动生成的条件
用户没有自定义拷贝构造函数,拷贝赋值运算符,移动赋值运算符,析构函数

通常像下面这样,总是保证基类的先被移动构造,如果一个类不能被移动但是能够被拷贝的话,那么就用拷贝代替移动

MyClass(MyClass&& obj)
: Base{std::move(obj)}, value{std::move(obj.value)} {
}

/**********************************************/
Copy Assignment Operator
拷贝赋值运算符 自动生成的条件
用户没有自定义移动构造函数 和 移动赋值运算符

MyClass& operator= (const MyClass& obj) {
Base::operator=(obj); // - perform assignments for base class members
value = obj.value; // - assign new members
return *this; }

生成的拷贝赋值运算符 总是保证基类的成员先被赋值

/**********************************************/
Move Assignment Operator
move赋值运算符生成的条件
用户没有自定义 拷贝构造函数 拷贝赋值运算符 移动构造函数 析构函数

MyClass& operator= (MyClass&& obj) {
Base::operator=(std::move(obj)); 
// - perform move assignments for base class members
value = std::move(obj.value); // - move assign new members
return *this; }

生成的移动赋值运算符,总是保证基类的成员先被移动,要是不能被移动赋值但是可以被拷贝赋值,那就用拷贝赋值代替

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值