C++prime读书笔记(三)拷贝控制、运算重载与类型转换、对象继承、模板与泛型
创始人
2024-02-13 02:33:52
0

layout: post
title: C++prime读书笔记(三)拷贝控制、运算重载与类型转换、对象继承、模板与泛型
description: C++prime读书笔记(三)拷贝控制、运算重载与类型转换、对象继承、模板与泛型
tag: 读书笔记


C++Prime读书笔记

  • 第13章:拷贝控制
    • 拷贝、赋值与销毁
      • 拷贝构造函数
      • 拷贝初始化与直接初始化的区别
      • 拷贝赋值运算符
      • 析构函数
      • 三/五法则
      • 使用=default
      • 阻止拷贝=delete
    • 拷贝控制和资源管理

第13章:拷贝控制

当定义一个类时,我们显式或隐式地指定在此类型的对象拷贝、移动、赋值和销毁时做什么,这些操作统称为拷贝控制操作,一个类通过定义5中特殊的成员函数来控制这些操作,包括拷贝构造函数、拷贝赋值函数、移动构造函数、移动赋值运算符和析构函数

拷贝、赋值与销毁

拷贝构造函数

如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数

class Foo
{
public:Foo();  // 默认构造Foo(const Foo&); // 拷贝构造
};

注意:
1、当我们没有为类声明任何构造函数时,编译器为我们合成默认构造函数。
但拷贝构造不同,即使我们定义了其他构造函数,编译器也会为我们合成一个拷贝构造函数

2、拷贝构造接收的参数必须是自身类类型的引用,如果参数不是引用类型,则调用永远也不会成功,为了调用拷贝构造函数,我们必须拷贝它的实参,但为了拷贝实参,我们又要调用拷贝构造函数,如此无限循环。

拷贝初始化与直接初始化的区别

直接初始化时,我们实际上要求编译器使用普通的函数匹配,而使用拷贝初始化时,我们要求编译器将右侧运算对象拷贝到正在创建的对象,如果需要的话还会进行类型转换。

string dots(10, ','); //直接初始化
string s(dots);  // 直接初始化
string s2 = dots; // 拷贝初始化
string null-book = "99999=99999"; // 拷贝初始化
string nines = string(100, '9'); // 拷贝初始化

拷贝初始化不仅在使用=定义变量时会发生,在下列情况下也会发生:

  • 将一个对象作为实参传递给一个非引用类型的形参
  • 从一个返回类型为非引用类型的函数返回一个对象
  • 用花括号列表初始化一个数组中的元素或一个聚合类中的成员。

注: 1、某些类型还会对他们所分配的对象使用拷贝初始化,例如当我们使用insert或者push成员时,容器会对元素进行拷贝初始化,与之对应用emplace成员创建的元素都进行直接初始化
2、如果我们希望使用explicit构造函数就必须显式地使用直接初始化,不可使用隐式地拷贝初始化转换。

拷贝赋值运算符

与类控制对象如何初始化一样,类也可以控制对象如果进行赋值。
与处理拷贝构造函数一样,如果一个类未定义自己的拷贝赋值运算符,编译器会为它生成一个合成拷贝赋值运算符。作为一个例子,下边的代码等价于Sales_data的合成拷贝赋值运算符,合成拷贝赋值运算符返回一个指向其左侧运算对象的引用。

Sales_data&
Sales_data::operator=(const Sales_data &rhs)
{bookNo = rhs.bookNo;units_sold = rhs.units_sold;revenue = rhs.revenue;return *this;
}

析构函数

析构函数释放对象使用的资源,销毁对象的非static数据成员。与普通指针不同,智能指针是类类型,所以具有析构函数。
以下情况会调用析构函数:

  • 变量在离开其作用域时被销毁
  • 当一个对象被销毁时,其成员被销毁
  • 容器被销毁时,其元素被销毁
  • 对于动态分配的对象,当指向它的指针应用delete运算符时被销毁。
  • 对于临时对象,当创建它的完整表达式结束时被销毁。

当一个类未定义自己的析构函数时,编译器会为它定义一个合成析构函数,类似拷贝构造函数和拷贝赋值运算符,在(空)析构函数体执行完毕后,成员会被自动销毁,析构函数体自身并不直接销毁成员,成员是在析构函数体之后隐含的析构阶段中被销毁的,在整个对象销毁的过程中,析构函数体是作为成员销毁步骤之外的另一部分而进行的

三/五法则

C++中有三个基本操作可以控制类的拷贝操作:拷贝构造函数、拷贝赋值运算符和析构函数,在C++11新标准下,一个类还可以定义一个移动构造函数和一个移动赋值函数
当我们决定一个类是否要定义它自己版本的拷贝控制成员时,一个基本原则是首先确定这个类是否需要一个析构函数,通常对于析构函数的需求要比对拷贝构造函数或者赋值运算符的需求更加明显。如果这个类需要一个析构函数,我们几乎可以确定它也需要一个拷贝构造函数和一个拷贝赋值运算符

例如下边这个例子:HasPtr中有指针数据成员,因此需要析构函数来释放指针。另一方面,由于包含指针成员,如果使用合成的拷贝构造和拷贝赋值运算符,这些函数简单拷贝指针成员,意味着多个HasPtr对象可能指向相同的内存。

class HasPtr{
public:HasPtr(const std::string &s = std::string()): ps(new std::string(s)), i(0) {}~HasPtr(){delete ps;}// 错误:HasPtr还需要一个拷贝构造函数和一个拷贝赋值运算符HasPtr& operator=(const HasPtr &hasptr){ps = new std::string(*(hasptr.ps));i = hasptr.i;return *this;} HasPtr(const &hasptr){ps = new std::string(*(hasptr.ps));i = hasptr.i;return *this;}
private:std::string *ps;int i;	
};

三/五法则的第二条是“如果一个类需要一个拷贝构造函数,几乎可以肯定它也需要一个拷贝赋值运算符,反之亦然——如果一个类需要一个拷贝赋值运算符,几乎可以肯定它也需要一个拷贝构造函数。”

使用=default

我们可以通过将拷贝控制成员定义为=default来显式地要求编译器生成合成的版本,当我们在类内使用=default修饰成员时,合成的函数将隐式地声明为内联的(就像任何其他类内声明的成员函数一样)。如果不希望合成的成员是内联函数,应该只对成员的类外定义使用=default,就像下面例子中对于拷贝赋值运算符=所做的那样。

class Sales_data
{
public:// 拷贝控制成员使用defaultSales_data() = default;Sales_data(const Sales_data &) = default;Sales_data & operator= (const Sales_data &);~Sales_data() = default;
};
Sales_data& Sales_data::operator=(const Sales_data&) = default;

如果我们不希望合成的成员是内联函数,应该只对成员的类外定义使用=default。

阻止拷贝=delete

对于某些类来讲拷贝和赋值没有合理的意义,因此在定义这些类时必须采用某种机制阻止拷贝或赋值。例如iostream类阻止了拷贝,以避免多个对象写入或读取相同的IO缓冲。为了阻止拷贝,可以通过将拷贝构造函数和拷贝赋值运算符定义为删除的函数,这种删除函数的意思是:我们虽然声明了它们,但不能以任何方式使用它们。=delete通知编译器,我们不希望定义这些成员。与=default不同,=delete必须出现在函数第一次声明时,且析构函数不能是删除的成员

struct NoCopy
{NoCopy() = default(); // 使用合成默认构造函数NoCopy(const NoCopy&) = delete; // 阻止拷贝NoCopy &operator=(const NoCopy&) = delete; // 阻止赋值~NoCopy() = default;  // 使用合成的析构函数
};

注:合成的拷贝控制成员可能是删除的,如果一个类有数据成员不能默认构造、拷贝、复制或销毁,则对应的成员函数将被定义为删除的。

拷贝控制和资源管理

相关内容

热门资讯

曾经的爱 曾经的爱我自己来回答我可能是真的喜欢她但是,每次不知道为什么看到她就一中伤心的感觉不知道谁能告诉我这...
小公鸡不见偷偷的跟在小鸭子后面... 小公鸡不见偷偷的跟在小鸭子后面也下了水偷偷地这个词加上这个词的好处是小公鸡不见偷偷的跟在小鸭子后面也...
开紫钻一年多少钱? 开紫钻一年多少钱?我卖180 ,一年大概120 玩旋舞特适合用财富通开8.8折一共是211
关于韩剧 关于韩剧灰姑娘的姐姐吧,不错。还有一枝梅。狗与狼的时间,都好看。
谁小泰罗的电影? 谁小泰罗的电影?小泰罗奥特曼的电影? 你说的这个是奥特曼剧场版《奥特物语》网上搜一下就能找到
电纸书和mp4功能一样吗,买电... 电纸书和mp4功能一样吗,买电子书好还是mp4好啊?推荐一款吧?谢谢看你具体干什么了,如果喜欢看电子...
关于ff14的装备出售问题! ... 关于ff14的装备出售问题! 为什么好多装备无法在市场出售?紫装绿装不说,为什么普通白装也不能关于f...
为什么佛法的争论那么激烈? 为什么佛法的争论那么激烈?因为他们没有一个统一的经典,来指导他们,告诉他们真理. 不然他们就不会拜那...
为什么有的调皮美女不喜欢调皮男... 为什么有的调皮美女不喜欢调皮男人,不稳重没有安全感。她喜欢成熟有男人味安全感男人?大部分女人都喜欢成...
哪些男明星男人味儿彰显,成熟的... 哪些男明星男人味儿彰显,成熟的魅力撩动心弦让你沦陷?朱一龙,张若昀,李钟硕,李承铉,靳东等,这些男明...
天书奇谈里皇城里的盘龙石柱在哪... 天书奇谈里皇城里的盘龙石柱在哪阿、?点左上角的【寻】会出来一个框,里面有蟠龙石柱,点击左键会自动寻找...
50年前,长沙镖子岭。老烟头把... 50年前,长沙镖子岭。老烟头把他的旱烟在地上敲了敲:“下不下去喃?”独眼的小伙子说:“不去,电视剧5...
如何评价演员袁姗姗,她是不是真... 如何评价演员袁姗姗,她是不是真的不适合娱乐圈?因人而异吧,我个人还是比较喜欢她的,虽然长得确实不漂亮...
各路大神? 各路大神?既然可以发送、接受文件,可以确认电脑蓝牙驱动正常,可以连接手机蓝牙。接下来要确认手机有蓝牙...
三国演义诸葛亮的资料 三国演义诸葛亮的资料三国演义诸葛亮的资料去看史书就知道了诸葛亮子孔明,号卧龙,南阳人,著作出师表,隆...
如何隐藏一个硬盘分区,只能我自... 如何隐藏一个硬盘分区,只能我自己能进,别人都看不到。用patition magic 隐藏分区
韩剧名字其中两个字是爱情 韩剧名字其中两个字是爱情没关系,是爱情啊--赵寅成,孔孝真最佳爱情--车胜元,孔孝真爱情能用钱买吗-...
谁炒股一年能挣百万 谁炒股一年能挣百万规定时间 数量 你以为在算加减法 能有正解答案 股市是有时长时短 时多时少 这是没...
一个你不爱的人 一个你不爱的人面拒绝 呵呵,女的都出来了,这问题到是比较符合你们!其他的怎么女的回答的那么少??
有人有曲的成语 有人有曲的成语曲尽人情【读音】qū jìn rén qíng【释义】委婉周到地把人之常情或世态充分体...