CppPrimer笔记 Chapter13 拷贝控制

来源:互联网 发布:手机磁力链接播放软件 编辑:程序博客网 时间:2024/05/22 17:28

CppPrimer笔记 Chapter13 拷贝控制

标签: Cpp


  • CppPrimer笔记 Chapter13 拷贝控制
    • 概述
    • 拷贝赋值与销毁131
    • 拷贝控制和资源管理132
    • 动态内存管理类135
    • 对象移动136


概述

一个类通过定义五中特殊成员函数来控制对象的:
拷贝 移动 赋值 销毁
包括
拷贝构造函数 拷贝赋值运算符 移动构造函数 移动赋值运算符 析构函数

拷贝,赋值与销毁(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限定符没有这个要求
0 0
原创粉丝点击