这部分主要讲=default和=delete的用法。之前还有两个小内容,简单介绍一下:
(1)explicit关键字用于多实参构造函数,例如:
class P
{
public:
explicit P(int a, int b, int c)
{
cout << "P(int a, int b, int c)" << endl;
}
};
P p = {1, 2, 3}; //报错,不能将initializer_list隐式转换为P
但是如果定义了接受initializer_list<int>为参数的构造函数,就将会调用这个版本,不会报错。
(2)rang-based for。比较简单,就不详细说了。
一、概述
看一个小例子:
class Zoo
{
public:
Zoo(int i1, int i2) : d1(i1), d2(i2) { }
Zoo(const Zoo&) = delete;
Zoo(Zoo&&) = default; //move constructor
Zoo& operator=(const Zoo&) = default;
Zoo& operator=(const Zoo&&) = delete; //move assignment operator
virtual ~Zoo() { }
private:
int d1, d2;
};
Big_Three变成了Big_Five,增加了move constructor和move assignment operator,均和右值引用有关,具体含义先不谈,要记住的是这五个函数都有默认定义,所以都可以加上=default
二、=default 和 =delete的各种情况
(1)拷贝构造和拷贝赋值只能有一个定义。(猜想Big-Five是否都是这样的?)
(2)=default只能用于Big_five,用在普通函数上会报错
(3)如果析构函数定义为删除的,语法上是可以的,但是在使用对象时肯定会报错,因为一个对象的生命周期总会结束的。
三、No-Copy 和 Private-Copy
1. No-Copy:将拷贝构造函数和拷贝赋值运算符定义为删除的
struct NoCopy
{
NoCopy() = default;
NoCopy(const NoCopy&) = delete;
NoCopy &operator=(const NoCopy&) = delete;
~NoCopy() = default;
//other members
};
2. NoDtor:将析构函数定义为删除的
struct NoDtor
{
NoDtor() = default;
~NoDtor() = delete;
};
NoDtor nd; //error
NoDtor *p = new NoDtor(); //OK
delete p; //error
(这里有一点不太理解,为什么new可以,定义变量不可以?)
原因:因为nd是定义在栈上的变量,在作用域结束以后会自动调用析构函数,调用析构函数是由操作系统自动完成的,当编译器发现无法调用析构函数时就会报错。而new出来的对象是在堆上的,操作系统不会自动调用析构函数,需要我们手动销毁,只要我们不销毁就不会调用析构函数,也就不会出错。
3. Private-Copy:将拷贝构造函数和拷贝构造运算符定义为私有的
class PrivateCopy
{
private:
PrivateCopy(const PrivateCopy&);
PrivateCopy operator=(const PrivateCopy&);
public:
PrivateCopy() = default;
~PrivateCopy();
};
这个class不能被ordinary user code拷贝,但是可以被friends和members拷贝。