C++析构、拷贝、赋值、移动拷贝函数的几个知识点(不全)
怕忘了,写这:析构函数不会释放指针成员指向的对象(但智能指针类时有自己的析构函数的)。
析构函数中成员按初始化顺序的逆序销毁。内置类型没有析构函数。
继承体系中,派生类析构函数最先执行,然后是其基类的析构函数,以此类推,沿着继承体系的反方向往上。
众所周知,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++析构、拷贝、赋值、移动拷贝函数的几个知识点(不全)的更多相关文章
- 《Effective C++》阅读总结(二):类的构造、析构和赋值
今天是周六早上,但很不幸待会儿还是要去公司,本月kpi还剩一些工作要做,这个月计划的Effective C++学习,也基本完成了,最后一章节模板相关那部分还看不太懂,就大概过了一遍.现在是收尾总结阶段 ...
- 构造函数和初始化表、this指针与常函数、析构函数、拷贝构造与拷贝赋值(day05)
十四 构造函数和初始化表 ... 初始化表 )语法形式 class 类名{ 类名(形参表):成员变量1(初值),...{} }; )必须要使用初始化表的场景 -->如果有类 类型的成员变量,而该 ...
- c++不自动生成相关函数比如赋值、拷贝函数
默认情况下,如果没有明确声明某些函数比如赋值.拷贝函数,c++会自动生成这些函数,通常他们是对成员进行by-value拷贝,有些时候,赋值.拷贝对象并无什么意义或者不合理,比如对于socket或者th ...
- C++ class内的=重载,拷贝赋值函数copy op=,重载示例。必须是class内
#include <iostream> // overloading "operator = " inside class // = 是一元操作符.不写,编译器会提供 ...
- C++ Primer : 第十三章 : 拷贝控制之拷贝、赋值与销毁
拷贝构造函数 一个构造函数的第一个参数是自身类类型的引用,额外的参数(如果有)都有默认值,那么这个构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是一个引用类型. 合成的拷贝构造函数 在我们没 ...
- [c++基础]3/5原则--拷贝构造函数+拷贝赋值操作符
/* * main.cpp * * Created on: Apr 7, 2016 * Author: lizhen */ #include <iostream> #include &qu ...
- 拷贝构造和拷贝赋值、静态成员(static)、成员指针、操作符重载(day06)
十七 拷贝构造和拷贝赋值 浅拷贝和深拷贝 )如果一个类中包含指针形式的成员变量,缺省的拷贝构造函数只是复制了指针变量的本身,而没有复制指针所指向的内容,这种拷贝方式称为浅拷贝. )浅拷贝将导致不同对象 ...
- std::string的拷贝赋值研究
说明:以下涉及的std::string的源代码摘自4.8.2版本.结论:std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相同的数据地址. // std::string类定义type ...
- 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 ...
随机推荐
- Elasticsearch系列
一.Elasticsearch简介 二.elasticsearch集群监控相关
- 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 ...
- Mysql:自动化备份
简介 在这个数据为王的时代,数据的备份十分重要,这里就分享一篇mysql数据库自动备份的脚本(是从网上搜到的),其将配置文件和备份脚本分离,提高了安全性,脚本风格规范严谨,分享给大家希望对需要的小伙伴 ...
- Kittenblock画笔基础,移动留下痕迹的蝴蝶,图形化编程经验分享
Kittenblock画笔基础,移动留下痕迹的蝴蝶,图形化编程经验分享 跟很多学生聊过,很多学生不是不努力,只是找不到感觉.有一点不可否认,同样在一个教室上课,同样是一个老师讲授,学习效果迥然不同.关 ...
- 草台班子--Window10文件管理器默认显示图片DPI及位深信息
草台班子--Window10文件管理器默认显示图片DPI及位深信息 经常处理一些图片的DPI/PPI信息,总是需要找软件打开确认,通过Windows10文件浏览器可以默认显示图片的DPI信息 ...
- 性能优化-CPU占用过高问题排查
1. 性能优化是什么? 1.1 性能优化就是发挥机器本来的性能 1.2 性能瓶颈在哪里,木桶效应. CPU占用过高 1.现象重现 CPU占用过高一般情况是代码中出现了循环调用,最容易出现的情况有几 ...
- PYTHON 学习笔记3 元组、集合、字典
前言 在上一节的学习中.学习了基本的流程控制语句,if-elif-else for while 等,本节将拓展上一节学习过的一些List 列表当中操作的一些基本方法,以及元祖.序列等. 列表扩展 我们 ...
- 文本处理命令 cat more less cut wc sort uniq
1.cat cat主要功能: 1.一次显示整个文件. cat filename 2.从键盘创建一个文件. cat > filename (只能创建新文件,不能编辑已有文件). 1 ...
- 一键安装apache-2.4.38脚本
[root@lamp scripts]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core) [root@lamp scripts ...
- 【python-leetcode206-翻转链表】反转链表
问题描述: 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL输出: 5->4->3->2->1->NULL进阶:你可 ...