怕忘了,写这:析构函数不会释放指针成员指向的对象(但智能指针类时有自己的析构函数的)。

析构函数中成员按初始化顺序的逆序销毁。内置类型没有析构函数。

继承体系中,派生类析构函数最先执行,然后是其基类的析构函数,以此类推,沿着继承体系的反方向往上。


众所周知,C++的类如果没有默认构造函数,会自动生成一个。

同理,如果没有复制构造函数即A::A(const A&){}这个函数 ,则系统也会自动生成一个,但这个自动生成的复制构造函数不一定满足我们的要求。析构函数也会自动生成(如果没定义的话)。

比如下面的例子:

 class A{
public:
int* a;
int b;
A()=default;
A(int x):a(new int()){b=x;}
~A(){delete a;cout<<"我删除a了!"<<endl;}
};

其中我们定义了默认构造函数、另一个重载版本的构造函数。但是我们没有定义复制构造函数,所以系统自动帮我们生成了一个,作用大致可以理解为下面的函数:

A(const A& another){
a=another.a;
b=another.b;
}

我们也没有定义析构函数,系统也自动生成了一个,类似下面:

~ A(){
  delete a;
  delete b;
}

而我们注意到类A中有一个指针成员,那么在默认的拷贝构造函数中就会简单的复制指针到另一个A变量。如A x1(x2); x1和

x2的指针成员a是一样的。这根本不是我们的本意,我们的本意是在上面代码第5行:每个A变量的成员a应该初始化为一个新建int变量的地址,而不同A变量之间的成员a应该是不同的。

所以可能出现的问题就是:如果x2空间被释放了,x1的成员a也就无效了,其指向的值是未定义的。。

或者可能有另一个函数这样定义,更好理解:

void f(A temp)
{
//.......
}

那么调用f(x1)的时候,会先调用拷贝构造函数,复制一个x1的副本作为形参。然后这个副本temp就拥有了和x1一样的成员a,当退出函数f的时候,temp的成员a被析构释放,这导致x1的成员a也变成了野指针。

我们自己定义好正确的拷贝构造函数即可解决上面的问题。

所以,遇到类的成员有非普通类型的时候(如指针),就一定要自己写拷贝构造函数、重载赋值符、移动构造函数、重载移动赋值符、析构函数。

注意:如果只定义了移动构造函数 or 重载移动赋值符,那么编译器是不会自动帮你生成拷贝构造函数和重载赋值符的,而是会默认定义为删除的(=delete;)。


下面看下各种构造函数和拷贝函数,加深下印象。

要注意的是如果我们有A x1;

A x2=x1;和 A x3;x3=x1;是不一样的阿!

前者是声明时就初始化,属于拷贝初始化。调用的是拷贝构造函数( A& (const A& another){ }

后者是先声明,默认初始化。然后赋值。先调用默认构造函数(A( ) {  }),再调用重载赋值符,即( A& operator=(const A& a) )

 class A
{
private:
int x;
public:
A(){cout<<"A()"<<endl;} //默认构造函数
A(int&& a){x=a;cout<<"A(int&& a)"<<endl;} //重载的构造函数
A(A&& a){cout<<"A(A&& a)"<<endl;x=a.x;} //移动拷贝函数
A(A& a){cout<<"A(A& a)"<<endl;x=a.x;} //拷贝构造函数
A& operator=(const A&& a){if(this!=&a){x=a.x;}cout<<"A& operator=(A&&)"<<endl;} //移动赋值符
A& operator=(const A& a){if(this!=&a){x=a.x;}cout<<"A& operator=(A&)"<<endl;} //拷贝赋值符
~A(){cout<<"删除了!"<<endl;} //析构函数
};
int main()
{ int a=;
A x1;
A x2();
A x3=move(x2);
A x4=x3;
x1=move(x2);
x2=x3;
getchar();
return ;
}

输出:


另外一个知识点,好像之前看剑指offer也看过来着,当时印象不深:

编写类的赋值运算符重载时,几个要求:
1.自赋值能正常运行不报错。
2.赋值运算符一般都集合了复制构造函数和析构函数二者的功能。

3.不要先删数据,再拷贝新数据到this的空间!这样容易删完了自己的,但拷贝又异常失败了,那该实例原来的数据就没得了

例子:

 A& operator=(const A& x){
if(this!=&x){
A temp(x);
a=temp.a;
b=temp.b;
//......//
}
return *this;
}

这样的目的是避免在函数中new空间时抛异常,会导致之前实例的数据变化。上面代码中的临时变量A如果申请失败,函数直接退出,不会影响原先该实例的数据。

先建立一个临时变量,然后依次赋值成员变量的值到this的成员,最后返回当前实例的引用,这样函数退出时temp也被自动析构释放。当然这个例子是建立在已经写好复制构造函数和析构函数的前提下,否则这个函数中 程序员应该自己写好对应的功能。

C++析构、拷贝、赋值、移动拷贝函数的几个知识点(不全)的更多相关文章

  1. 《Effective C++》阅读总结(二):类的构造、析构和赋值

    今天是周六早上,但很不幸待会儿还是要去公司,本月kpi还剩一些工作要做,这个月计划的Effective C++学习,也基本完成了,最后一章节模板相关那部分还看不太懂,就大概过了一遍.现在是收尾总结阶段 ...

  2. 构造函数和初始化表、this指针与常函数、析构函数、拷贝构造与拷贝赋值(day05)

    十四 构造函数和初始化表 ... 初始化表 )语法形式 class 类名{ 类名(形参表):成员变量1(初值),...{} }; )必须要使用初始化表的场景 -->如果有类 类型的成员变量,而该 ...

  3. c++不自动生成相关函数比如赋值、拷贝函数

    默认情况下,如果没有明确声明某些函数比如赋值.拷贝函数,c++会自动生成这些函数,通常他们是对成员进行by-value拷贝,有些时候,赋值.拷贝对象并无什么意义或者不合理,比如对于socket或者th ...

  4. C++ class内的=重载,拷贝赋值函数copy op=,重载示例。必须是class内

    #include <iostream> // overloading "operator = " inside class // = 是一元操作符.不写,编译器会提供 ...

  5. C++ Primer : 第十三章 : 拷贝控制之拷贝、赋值与销毁

    拷贝构造函数 一个构造函数的第一个参数是自身类类型的引用,额外的参数(如果有)都有默认值,那么这个构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是一个引用类型. 合成的拷贝构造函数   在我们没 ...

  6. [c++基础]3/5原则--拷贝构造函数+拷贝赋值操作符

    /* * main.cpp * * Created on: Apr 7, 2016 * Author: lizhen */ #include <iostream> #include &qu ...

  7. 拷贝构造和拷贝赋值、静态成员(static)、成员指针、操作符重载(day06)

    十七 拷贝构造和拷贝赋值 浅拷贝和深拷贝 )如果一个类中包含指针形式的成员变量,缺省的拷贝构造函数只是复制了指针变量的本身,而没有复制指针所指向的内容,这种拷贝方式称为浅拷贝. )浅拷贝将导致不同对象 ...

  8. std::string的拷贝赋值研究

    说明:以下涉及的std::string的源代码摘自4.8.2版本.结论:std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相同的数据地址. // std::string类定义type ...

  9. python中的赋值与拷贝(浅拷贝与深拷贝)

    1.赋值与拷贝 直接赋值(b=a)是传引用,b改动a也会改动. a = [1, 2, 3, 4] b = a b[1] = 999 print(a, b) #[1, 999, 3, 4] [1, 99 ...

随机推荐

  1. Elasticsearch系列

    一.Elasticsearch简介 二.elasticsearch集群监控相关

  2. HDU6440 Dream(费马小定理+构造) -2018CCPC网络赛1003

    题意: 给定素数p,定义p内封闭的加法和乘法,使得$(m+n)^p=m^p+n^p$ 思路: 由费马小定理,p是素数,$a^{p-1}\equiv 1(mod\;p)$ 所以$(m+n)^{p}\eq ...

  3. Mysql:自动化备份

    简介 在这个数据为王的时代,数据的备份十分重要,这里就分享一篇mysql数据库自动备份的脚本(是从网上搜到的),其将配置文件和备份脚本分离,提高了安全性,脚本风格规范严谨,分享给大家希望对需要的小伙伴 ...

  4. Kittenblock画笔基础,移动留下痕迹的蝴蝶,图形化编程经验分享

    Kittenblock画笔基础,移动留下痕迹的蝴蝶,图形化编程经验分享 跟很多学生聊过,很多学生不是不努力,只是找不到感觉.有一点不可否认,同样在一个教室上课,同样是一个老师讲授,学习效果迥然不同.关 ...

  5. 草台班子--Window10文件管理器默认显示图片DPI及位深信息

    草台班子--Window10文件管理器默认显示图片DPI及位深信息    ​ 经常处理一些图片的DPI/PPI信息,总是需要找软件打开确认,通过Windows10文件浏览器可以默认显示图片的DPI信息 ...

  6. 性能优化-CPU占用过高问题排查

    1. 性能优化是什么? 1.1 性能优化就是发挥机器本来的性能 1.2 性能瓶颈在哪里,木桶效应.   CPU占用过高 1.现象重现 CPU占用过高一般情况是代码中出现了循环调用,最容易出现的情况有几 ...

  7. PYTHON 学习笔记3 元组、集合、字典

    前言 在上一节的学习中.学习了基本的流程控制语句,if-elif-else for while 等,本节将拓展上一节学习过的一些List 列表当中操作的一些基本方法,以及元祖.序列等. 列表扩展 我们 ...

  8. 文本处理命令 cat more less cut wc sort uniq

    1.cat       cat主要功能: 1.一次显示整个文件. cat filename 2.从键盘创建一个文件. cat > filename   (只能创建新文件,不能编辑已有文件). 1 ...

  9. 一键安装apache-2.4.38脚本

    [root@lamp scripts]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core) [root@lamp scripts ...

  10. 【python-leetcode206-翻转链表】反转链表

    问题描述: 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL输出: 5->4->3->2->1->NULL进阶:你可 ...