CppPrimer笔记 Chapter13 拷贝控制
标签: Cpp
概述
一个类通过定义五中特殊成员函数来控制对象的:
拷贝 移动 赋值 销毁
包括
拷贝构造函数 拷贝赋值运算符 移动构造函数 移动赋值运算符 析构函数
拷贝,赋值与销毁(13.1)
- 若一个构造函数的第一个参数是自身类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数.
- 第一个参数必须为引用,通常为const.函数一般不应是
explicit
- 即使我们定义了自己的拷贝构造函数,编译器仍会合成拷贝构造函数.(不同于构造函数)
- 赋值运算符通常应返回指向左侧运算对象的引用
- 析构函数为
~className();
,不能重载,一类唯一. - 成员按初始化顺序逆序销毁(销毁是隐式的,发生在函数体后)
- 隐式销毁一个内置指针类型的成员不会delete对象,那么一个对象的指针或引用离开作用域时,析构函数不会执行.
- 对于一个需要自定义析构函数的类,一般需要自定义的拷贝与赋值操作
- 定义删除的函数来阻止默认生成的拷贝与赋值默认函数
NoCopy(const NoCopy&) = delete;//阻止拷贝
//阻止赋值
NoCopy &operator=(const NoCopy&) = delete; - 析构函数不能是删除成员
- 当不可能拷贝,赋值或销毁类的成员时,类的合成拷贝控制成员就被定义为删除的(P450,P476,P553,P751)
拷贝控制和资源管理(13.2)
- 对赋值运算符来说,一个好的方法是在销毁左侧运算对象资源之前拷贝右侧运算对象.否则如下,当rhs与本对象为同一个对象时,
delete ps
会释放*this和rhs指向的string
HasPtr& HasPtr::operator= (const HasPtr &rhs)
{
delete ps;
ps = new string(*(rhs.ps));
i = rhs.i;
return *this;
}
动态内存管理类(13.5)
- 在新内存中构造
string
等对象时,需调用move
,否则会使用string
的拷贝构造函数 - 我们通常不为
move
提供一个using
声明,而直接使用std::move()
对象移动(13.6)
- 标准库容器,string,与shared_ptr类支持移动与拷贝,IO与unique_ptr可以移动但不能拷贝
- 左值与右值绑定
int i = 42;
int &r = i;//ok
int &&rr = i;//error:右值引用不能绑定到左值上
int &r2 = i * 42;//error:i*42是右值
const int &r3 = i * 42;//ok 可以将一个const的引用绑定到一个右值上
int &&rr2 = i * 42;//ok
int &&rr1 = 42;//ok,字面常量是右值
int &&rr3 = rr1;//错误,表达式rr1是左值
- 利用
int &&rr3 = std::move(rr1);
来获得绑定到左值上的右值引用.意味着:除了对rr1赋值或销毁它外,我们将不再使用它.
即:可以销毁一个移后源对象(rr1),也可以赋予它新值,但不能使用一个移后源对象 - 移动操作后,移后源对象必须保持有效,可析构状态,但用户不能对其值进行任何假设.
- 当一个类没有定义任何自己版本的拷贝控制成员,且其所有数据成员都能移动构造或移动赋值时,编译器才会为它合成上述两个函数.否则,会是删除的
- 函数的返回值
StrVec getVec(){StrVec x; return x;}
StrVec v1,v2;
v1 = v2;
v2 = getVec();
若StrVec
定义了移动拷贝构造与赋值函数,那么会在getVec()
的return
时
1. 调用移动构造函数,创建一个新的对象(临时对象,右值)
2. 析构函数内的局部变量
3. 调用移动赋值函数,将创建的右值移动给`v2`
4. 调用析构函数,析构创建的临时对象
若StrVec
未定义了移动拷贝构造与赋值函数,那么会在getVec()
的return
时
1. 调用拷贝构造函数,创建一个新对象(临时)
2. 析构函数内部的局部变量
3. 调用拷贝赋值函数,将创建的右值拷贝给`v2`
4. 调用析构函数,析构创建的临时对象
- 若类有可用的拷贝构造函数而没有移动构造函数,而其对象是通过拷贝构造函数来”移动”的
uninitialized_copy(make_move_iterator(begin()),make_move_iterator(end()),first);
construct使用移动构造函数来构造元素
- 区分移动和拷贝的重载函数通常是两个版本 一个
const T&
一个T&&
- 利用
&
与&&
像const
一样置于函数参数列表后(引用限定符),限定返回值是左值还是右值,避免s1+s2="word"
这样的语句
注意,同const一样,在声明与定义时均需加上
引用限定符和const限定符,同时出现,放在const后
即const &
- 定义多个同名同参的成员函数,则要么必须对所有函数加上引用限定符(不同的),要么都不加. 但
const
限定符没有这个要求