从今天开始,开始刷数据结构
书《数据结构与算法分析——C++语言描述(第四版)》
当数据成员含有指针时,默认操作很可能就会不起作用(如指针由某个对象成员函数定址的时候),自己写五大函数,实现深拷贝
//五大函数
class IntCell
{
public:
explicit IntCell(int initialValue = 0) { p = new int{ initialValue }; }
~IntCell() { delete p; } //析构
IntCell(const IntCell &rhs) {//拷贝构造
p = new int{ *rhs.p };
}
IntCell(IntCell && rhs) :p{ rhs.p } {//移动构造
rhs.p = nullptr;
}
IntCell & operator=(const IntCell &rhs) {
if (this != &rhs)
*p = *rhs.p;
return *this;
//C++11的拷贝和交换格式书写
//IntCell copy = rhs;
//swap(*this, copy); //3次移动
//return *this;
}
IntCell & operator=(IntCell && rhs) {
swap(p, rhs.p); //逐项赋值
return *this;
}
int read()const { return *p; }
void write(int x) { *p = x; }
private:
int *p;
};
1、
由于单参数隐式类型转换,在隐式类型中创建一个临时对象,这个对象是的赋值(或函数参数)兼容
没有的话,则
IntCell obj;
obj = 37; //不应该编译:类型不匹配
可以实现,由于内部
IntCell temporary = 37;
obj = temporary;
2、
C++11:产生大家熟悉的左值对应的右值(标识临时性对象),以此就会有传右值引用调用 && ,此时变通过move而不是复制来实现
因为有时候,我们要的只是那个值,并不想要整体的一个复制;有时候交换,也只是想交换两个数的值,目的是移动,而不是复制;
...std::move()函数能够把任何左值(或右值)转换成右值,使一个值易于移动。例如swap函数:
void swap1(vector
&x, vector
&y)
{//3次赋值
vector
tmp = x;
x = y;
y = tmp;
}
void swap2(vector
&x, vector
&y) { vector
tmp = static_cast
&&>(x); x = static_cast
&&>(y); y = static_cast
&&>(tmp); } void swap3(vector
&x, vector
&y) {//3次移动 vector
tmp = move(x); x = move(y); y = move(tmp); }
且在C++11中,对象看到函数返回值是传值返回时可以使用移动语义
那
IntCell(IntCell && rhs) :p{ rhs.p } {//移动构造
rhs.p = nullptr; //是不是因为值移到别的变量上了,所以置空?
}
3、
注意移动赋值采用 逐项赋值 而拷贝赋值的拷贝和交换格式则采用 3次交换,由于swap函数里也有 = ,用错了将会导致相互无终止的递归