c++三五法则(适合学完一遍不怎么清楚的童鞋)
有三个基本操作可以控制类的拷贝操作:拷贝构造函数、拷贝赋值运算符和析构函数。而且,在新标准下,一个类还可以定义一个移动构造函数和一个移动赋值运算符。这些操作通常应该被看作一个整体。通常,只需要其中一个操作,而不需要定义所有操作的情况是很少见的。
需要析构函数的类也需要拷贝和赋值操作。当我们决定一个类是否需要定义它自己版本的拷贝控制成员时,一个基本原则是首先确定这个类是否需要一个析构函数。如果一个类需要自定义析构函数,几乎可以肯定它也需要自定义拷贝赋值运算符和拷贝构造函数。
需要拷贝操作的类也需要赋值操作,反之亦然。
如果一个类需要一个拷贝构造函数,几乎可以肯定它也需要一个拷贝赋值运算符。反之亦然——如果一个类需要一个拷贝赋值运算符,几乎可以肯定它也需要一个拷贝构造函数。然而,无论是需要拷贝构造函数还是需要拷贝赋值运算符都不必然意味着也需要析构函数。
1. 需要析构函数的类也需要拷贝构造函数和拷贝赋值函数。
通常,若一个类需要析构函数,则代表其默认的析构函数不足以释放类所拥有的资源,其中最典型的就是指针成员(析构时需要手动去释放指针指向的内存)。所以,若存在自定义(且正确)的析构函数,但使用默认的拷贝构造函数,那么拷贝过去的也只是指针,此时两个对象的指针变量同时指向同一块内存,指向同一块内存的后果很有可能是在两个对象中的析构函数中先后被释放两次。所以需要额外的拷贝控制函数去控制相应资源的拷贝。
所以这类例子的共同点就是:一个对象拥有额外的资源(指针指向的内存),但另一个对象使用默认的拷贝构造函数也同时拥有这块资源。当一方对象被销毁后,析构函数释放了资源,这时另一个对象便失去了这块资源(但程序员还不知道)。
class person
{
public:std::string *name;int age;person(const char* the_name, int the_age){name = new std::string(the_name);age = the_age;}~person(){delete name;}
};int main(void)
{person a("me", 20);person b(a);std::cout << *b.name << std::endl;return 0;
}
在上面的代码中对象b使用默认的拷贝构造函数拷贝对象a的值,这个程序没有什么实际意义。在main函数返回时,a,b变量会分别被析构,它们的成员name指向同一块内存,所以在程序结束时便会发生错误。
2. 需要拷贝操作的类也需要赋值操作,反之亦然。需要拷贝操作代表这个类在拷贝时需要进行一些额外的操作。赋值操作=先析构+拷贝,所以拷贝需要的赋值也需要。反之亦然。
3. 析构函数不能是私有的。如果类的析构函数是私有的,那么成员便无法销毁。所以在程序中不能定义这个类的对象。可以动态分配该对象并获得其指针,但无法销毁这个动态分配的对象(delete 失效)。若上面的类的定义是
class person
{
public:std::string *name;int age;person(const char* the_name, int the_age){name = new std::string(the_name);age = the_age;}
private:~person(){delete name;}
};
则在main函数中定义变量a,b就会发生编译错误,然而,这样的定义却可以通过编译
person *p;
p = new person("me", 20)
但是,这样动态分配的变量是不能被释放的,在调用 delete p 会发生编译错误, 内存泄露就这样发生了。
4. 如果一个类有私有的或不可访问的析构函数,那么其默认和拷贝构造函数会被定义为私有的。
如果没有这条规则,可能会创造出无法被私有的对象。 理论上来说,当析构函数不能被访问时,任何静态定义的对象都不能通过编译器的编译,所以这种情况只会出现在与动态分配有关的拷贝/默认构造函数身上。
5. 如果一个类有const或引用成员,则不能使用默认的拷贝赋值操作。
原因很简单,const或引用成员只能在初始化时被赋值一次,而默认的拷贝赋值操作会对所有成员都进行赋值。显然,它不能赋值const和引用成员,所以默认的拷贝构造函数不能被使用,即会被定义为私有的。
C++ 三/五法则(总结的真棒)
当定义一个类时,我们显式地或隐式地指定了此类型的对象在拷贝、赋值和销毁时做什么。一个类通过定义三种特殊的成员函数来控制这些操作:拷贝构造函数、拷贝赋值运算符和析构函数。
拷贝构造函数定义了当用同类型的另一个对象初始化新对象时做什么,拷贝赋值运算符定义了将一个对象赋予同类型的另一个对象时做什么,析构函数定义了此类型的对象销毁时做什么。我们将这些操作称为拷贝控制操作。
由于拷贝控制操作是由三个特殊的成员函数来完成的,所以我们称此为“C++三法则”。在较新的 C++11 标准中,为了支持移动语义,
又增加了移动构造函数和移动赋值运算符,这样共有五个特殊的成员函数,所以又称为“C++五法则”。
也就是说,“三法则”是针对较旧的 C++89 标准说的,“五法则”是针对较新的 C++11 标准说的。
为了统一称呼,后来人们把它叫做“C++ 三/五法则”。
“需要析构函数的类也需要拷贝和赋值操作”
从“需要析构函数”可知,类中必然出现了指针类型的成员(否则不需要我们写析构函数,默认的析构函数就够了),所以,我们需要自己写析构函数来释放给指针所分配的内存来防止内存泄漏。
那么为什么说“也需要拷贝构造函数和赋值操作”呢?原因是:类中出现了指针类型的成员,必须防止浅拷贝问题。所以需要自己书写拷贝构造函数和拷贝赋值运算符,而不能使用默认的拷贝构造函数和默认的拷贝赋值运算符。
“需要拷贝操作的类也需要赋值操作,反之亦然”
“析构函数不能是删除的成员”
如果析构函数是删除的,那么无法销毁此类型的对象。对于一个删除了析构函数的类型,编译器不允许定义该类型的变量或创建该类的临时对象。而且,如果一个类有某个成员的类型删除了析构函数,我们也不能定义该类的变量或临时对象。
c++三五法则(适合学完一遍不怎么清楚的童鞋)相关推荐
- python语言适合做什么生意好_学完python可以从事哪些行业?
随着人工智能和大数据的兴起,Python受到了越来越多人的关注,一跃成为最受欢迎的编程语言之一.Python如此火爆,发展前景怎么样?学完后可以做什么呢?下面,千锋上海带大家了解一下. Python到 ...
- ERP项目介绍——适合刚学完SSH的朋友
前言 ERP项目是我学完SSH框架后做的第二个项目练习,第一个是前面介绍的JYUOA,这个项目的业务逻辑要比JYUOA复杂一下,但是在技术方面有很多使用的是类似的,像什么增删改查功能,还有公共功能抽取 ...
- 学python可以做什么知乎-学完Python后能做什么?
学习Python之后可以做什么工作: 第一:Python web开发 学完Python可以做web开发,因为现在中国学习Python的比较少,而招聘Python的却非常的多.所以Python web是 ...
- mfc编程淘汰了吗_工控编程,学完C++基础后再学什么?
完?那是什么程度?STL用得熟练吗?算法和数据结构掌握得怎么样呢?会写界面吗?BOOST呢? 像楼上所说的换一种语言,简直是痴人说梦,如果不深入一门语言,夸张一点说,就好比你会用很多编程语言写&quo ...
- 为什么你学了 N 遍 Spring Boot,至今还是学生项目?你的问题在这里 | 原力计划...
作者 | bugpool 出品 | CSDN博客 为什么你学了n遍<1天精通Spring Boot>,至今还是不精通Spring Boot,甚至还是停留在学生项目?真正要做项目就应该一步到 ...
- 学完python能做什么-学完Python后能做什么?
学习Python之后可以做什么工作: 第一:Python web开发 学完Python可以做web开发,因为现在中国学习Python的比较少,而招聘Python的却非常的多.所以Python web是 ...
- 怎么判断第几范式例题_学完就忘、做题就懵!初级会计怎么备考才能更高效?...
备考初级会计之路真是艰辛,目前官方政策初级会计职称是一年一考,早早开始学吧,又有惰性,总觉得时间还很多,报完名再开始学吧,又总是搞不透彻知识点,一个知识点需要一天甚至更多才能消化...... 很多时候 ...
- 计算机专业用学c4d吗,C4D软件学会要多久?学完后好就业吗?
随着计算机技术的不断革新,C4D早已广泛运用在各行各业之中,成为设计师们手中的好帮手.因此,不少的小伙伴们都想要通过学习C4D,在提升自我的同时,也能实现就业,那么C4D软件学会要多久呢? 因C4D的 ...
- python人工智能入门纳米学位_最近看到udacity的纳米学位很火,号称学完可以找到工作了,这是真的吗?...
2018年二月更新: 刷完了Coursera的Deep Learning Specialization,Coursera吃了大约二十几门Coding.Data Science的硬课(包括传说中的PGM ...
最新文章
- selenium webdriver - 结束进程
- 蛋白Ramachandran(拉氏图、拉曼图)的绘制和可视化
- java 反射遍历_java使用反射遍历类的字段
- 《C Primer Plus》读书笔记——存储类、链接和内存管理
- 【FFmpeg】FFmpeg常用基本命令(转载)
- Redis高可用:主从复制及哨兵模式
- case when then的用法
- 语法分析-C语言程序
- Objects.equals 有坑!!!
- w10恢复出厂设置_路由器如何恢复出厂设置
- 什么样的 python 可以可谓专业 PyPI 项目?刚刚学到三个概念:pep8、Sphinx、pytest与GitHub Action的集成
- webrtc在ubuntu14.04上的编译过程(12.04亦可)
- FireFox下竟然对HTML注释与IE下有不同的解析
- python 小说分析_Python文章相关性分析---金庸武侠小说分析
- 《一页纸项目管理》读书笔记
- [含论文+源码等]S2SH+mysql水费管理系统[包运行成功]
- 用友u8安装应用服务器输什么,用友u8服务器安装教程
- SAP MM 采购信息记录中价格单位转换因子的修改
- 我酸了,曝光几个腾讯 阿里P8前同事的副业收入
- clip和clip-path inset
热门文章
- SQL Server 中的时间算法
- 海量数据处理分析_BI
- 在OSI参考模型中,当两台计算机进行文件传输时,为防止中间出现网络故障而重传整个文件的情况,可通过在文件中插入同步点来解决,这个动作发生在( )
- ValueError: The QuerySet value for an exact lookup must be limited to one result using slicing.
- 2019第十届蓝桥杯C/C++ A组省赛 —— 第三题: 最大降雨量
- PAT (Basic Level) Practice (中文)1010 一元多项式求导 (25 分)
- 【Qt】QModbusTcpConnectionObserver类
- 【嵌入式】Ubuntu20.04执行arm-linux-gc 没有那个文件或目录
- 【Linux系统编程】进程间通信之共享内存
- 数据结构与算法之美01-开篇词