析构函数

C++ 面向对象高级开发 -- string

﹥>﹥吖頭↗ 提交于 2020-02-14 01:29:42
1. Object Based(基于对象) vs. Object Oriented(面向对象) Object Based: 面对的是单一class的设计; Object Oriented:面对的是多重classes的设计,class 和 class 之间的关系。 classes 的两个经典分类: class without pointer members -- complex class with pointer members -- string 2. 设计 string   2.1 防卫式声明   2.2 Big Three 若类内有指针成员,则一定要重写 拷贝构造函数,赋值构造函数和析构函数,即Big Three,执行 深拷贝 操作。编译器默认生成的 拷贝构造函数和赋值构造函数 只会进行 浅拷贝 ! 由于未能确定string对象的大小,因此类内提供一个指针成员,指向动态内存。   2.3 ctor 和 dtor 注意!在析构函数中,调用 delete [] m_data; 释放内存。 在右下角的函数应用中,一旦离开作用域 {} , s1 和 s2 自动调用析构函数释放内存。由于 p 是动态分配的内存,其生命周期在整个程序运行周期内。p 要到程序结束运行后,由系统自动回收泄露的内存。   2.4 copy ctor 和 copy op= 拷贝构造函数 拷贝赋值函数 分3个步骤:

构造/析构/赋值运算

左心房为你撑大大i 提交于 2020-02-12 17:33:29
条款05:了解C++默默编写并调用哪些函数   如果你没有声明任何构造函数,编译器也会成为你声明一个默认构造函数,默认构造函数和析构函数主要给编译器一个地方用来放置“藏身幕后”的代码,像是调用base classes和non-static成员变量的构造函数和析构函数。所有这些函数都是public且inline,编译器产生出来的析构函数是non-virtual,除非这个class的base class自身声明有virtual析构函数。   惟有当这些函数被需要(被调用),它们才会被编译器创建出来。即有需求,编译器才会创建它们。   至于拷贝构造函数和拷贝赋值操作符,编译器创建的版本只是单纯地将来源对象的每一个非静态成员变量拷贝到目标对象。   如一个类声明了一个构造函数(无论有没参数),编译器就不再为它创建默认构造函数。   编译器生成的拷贝赋值操作符:对于成员变量中有指针,引用,常量类型,我们都应考虑建立自己“合适”的拷贝赋值操作符。因为指向同块内存的指针是个潜在危险,引用不可改变,常量不可改变。 请记住:   编译器可以暗自为类创建默认构造函数、拷贝构造函数、拷贝赋值操作符,以及析构函数。 条款06:若不想使用编译器自动生成的函数,就该明确拒绝   通常如果你不希望类支持某一特定技能,只要不说明对应函数就是了。但这个策略对拷贝构造函数和拷贝赋值操作符却不起作用。因为编译器会

C++学习笔记7

瘦欲@ 提交于 2020-02-11 15:56:10
目录 六、动态联编与虚函数 1、联编的概念 2、静态联编 3、动态联编 4、虚函数 5、虚析构函数 6、纯虚函数和抽象类 六、动态联编与虚函数 1、联编的概念 联编是指一个计算机程序自身彼此关联(使一个源程序经过编译、 连接, 成为一个可执行程序) 的过程, 在这个联编过程中, 需要确定程序中的操作调用(函数调用) 与执行该操作(函数) 的代码段之间的映射关系, 按照联编所进行的阶段不同, 可分为静态联编和动态联编。 2、静态联编 静态联编又称静态束定、 早期联编、 前期联编。 静态联编是指联编工作是在程序编译链接阶段进行的, 静态联编又称早期联编, 因为这种联编是在程序开始运行之前完成的。 在程序编译阶段进行的这种联编又称静态束定, 在编译时就解决了程序中的操作调用与执行该操作代码间的关系, 确定这种关系又被称为束定, 编译时束定又称为静态束定。 静态联编就是, 编译器在程序运行前就知道调用什么函数做什么事 。 静态联编特点: 速度快效率高 。 3、动态联编 动态联编又称动态关联、 动态束定、 后期联编、 晚期联编。 动态联编是指编译程序在编译阶段并不能确切地知道将要调用的函数, 只有在程序执行时才能确定将要调用的函数, 为此要确切地知道将要调用的函数,要求联编工作在程序运行时进行, 这种在程序运行时进行的联编工作被称为动态联编。 C++规定: 动态联编是在 虚函数

不是GC打酱油,是人打酱油

倾然丶 夕夏残阳落幕 提交于 2020-02-11 06:47:03
不是GC打酱油,是人打酱油 之前在一个技术群里看到有人讨论内存释放问题,引发对GC的讨论,大体结论是GC不可靠,GC是打酱油的。 之所以得出这个结论,是因为我们大多时候使用的是GC.Collect(),同时并未提供大内存对象的析构函数并在析构函数中释放内存。 如有类: public class BufWrapper { private byte[] buf; public BufWrapper() { buf=new byte[1024*1024*2]; } ~BufWrapper() { buf=null; } } 对此写测试代码: BufWrapper br=null; while(true) { br=null; br=new BufWrapper(); } 这样的代码必定导致内存问题,原因在于虽然每次循环将上次创建的br设置为null使其引用数得以置零,但 .net的垃圾回收机制在默认情况下并不立即执行其析构函数,从而此对象中的buf不能被立即释放。所以,考虑为测试代码增加GC.Collect(): BufWrapper br=null; while(true) { br=null; br=new BufWrapper(); GC.Collect(); } 测试会发现,内存有所控制,但长时间观察,仍然呈波动上升趋势,而这应该正是大家怀疑GC的原因所在。其实,GC

python 析构函数:__del__()

断了今生、忘了曾经 提交于 2020-02-10 21:10:17
'''析构函数:__del__() 释放对象是自动调用'''class Person(object): def run(self): print("run") def eat(self, food): print("eat " + food) def __init__(self, name, age, height, weight): self.name = name self.age = age self.height = height self.weight = weight def __del__(self): print("这里是析构函数")per = Person("hanmeimei", 20, 170, 55)#释放对象del per#对象释放以后就不能再访问了#print(per.age)#在函数里定义的对象,会在函数结束时自动释放,这样可以用来减少内存空间的浪费def func(): per2 = Person("aa", 1, 1, 1)func()while 1: pass 来源: https://www.cnblogs.com/pygo/p/12292566.html

.Net Discovery系列之四 深入理解.Net垃圾收集机制(下)

自古美人都是妖i 提交于 2020-02-10 07:50:20
上一节给大家介绍了 .Net GC的运行机制,下面来讲下与GC相关的重要方法。 第二节.GC关键方法解析 1.Dispose()方法 Dispose可用于释放所有资源,包括托管的和非托管的,需要自己实现。 大多数的非托管资源都要求手动释放,我们应当为释放非托管资源公开一个方法,实现释放非托管资源的方法有很多种,实现IDispose接口的Dispose方法是最好的,这可以给使用你类库的程序员以明确的说明,让他们知道怎样释放你的资源;而且C#中用到的using语句快,也是在离开语句块时自动调用Dispose方法。 这里需要注意的是,如果基类实现了IDispose接口,那么它的派生类也必须实现自己的IDispose,并在其Dispose方法中调用基类中Dispose方法。只有这样的才能保证当你使用派生类实例后,释放资源时,连同基类中的非托管资源一起释放掉。 插曲:使用using与try+finally的区别 可以说2者没有任何区别,因为using只是编辑器级的优化,它与try+finally有着相同的作用,以下是一段使用using的代码,它在IL阶段也是以try+finally呈现的: C#: public partial class _Default : System.Web.UI.Page     {      protected void Page_Load(object

Interview_C++_day2

青春壹個敷衍的年華 提交于 2020-02-08 19:43:23
函数指针 在编译过程中,每一个函数都有一个入口地址,而函数指针就是指向该入口地址的指针。 #include<iostream> using namespace std; void fun1(int x) { cout << x << endl; } void fun2(int x) { cout << x+x <<endl; } int main() { void (*pf)(int); pf = fun1; pf(222); pf = fun2; pf(222); } 多态性和虚函数(virtual) 静态多态主要表现为重载,在编译时就确定了。 动态多态的基础是虚函数机制,在运行期间动态绑定,决定了基类调用哪个函数。 #include<iostream> using namespace std; class Shape { public: void show() { // 未定义为虚函数 cout << "Shape::show()" << endl; } void virtual show() { // 定义为虚函数 cout << "Shape::show()" << endl; } }; class Line : public Shape { public: void show() { cout << "Line::show()" << endl; } }; class

C++处理异常技巧-try,catch,throw,finally

一个人想着一个人 提交于 2020-02-08 19:15:51
异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制。 也许我们已经使用过异常,但是你会是一种习惯吗,不要老是想着当我打开一个文件的时候才用异常判断一下,我知道对你来说你喜欢用return value或者是print error message来做,你想过这样做会导致Memory Leak,系统退出,代码重复/难读,垃圾一堆…..吗?现在的软件已经是n*365*24小时的运行了,软件的健壮已经是一个很要考虑的时候了。 自序: 对写程序来说异常真的是很重要,一个稳健的代码不是靠返回Error Message/return Value来解决的,可是往往我们从C走过来,习惯了这样的方式。 仅以本文献给今天将要来临的流星雨把,还好我能在今天白天把这写完,否则会是第4个通宵了;同时感谢Jeffrey大师,没有他的SEH理论这篇文章只能完成一半,而且所有SEH列子的构想都来自他的指导;另外要感谢Scott Meyers大师,我是看他的书长大的;还要感谢Adamc / Darwin / Julian ,当然还有Nick的Coffee 内容导读: (请打开文档结构图来读这篇文章。) 本文包括2个大的异常实现概念:C++的标准异常和SHE异常。 C++标准异常:也许我们了解过他,但你有考虑过,其实你根本不会使用,你不相信,那我问你:垃圾回收在C++中怎么实现?其实不需要实现,C+

C++笔记11

ぃ、小莉子 提交于 2020-02-08 12:59:27
成员对象和封闭类 有成员对象的类叫封闭类 exp. class CTyre//轮胎类 { private: int radius;//半径 int width;//宽度 public: CTyre(int r,int w):radius(r),width(w){}//冒号后的是初始化列表,可以为每个成员变量附一个初始值 }; class CEngine//引擎类 { }; class CCar{//汽车类,封闭类 private: int price;//价格 CTyre tyre; CEngine engine;//tyre和engine是CTyre和CEngine的对象,tyre和engine就是成员对象engine用无参函数初始化 public: CCar(int p,int tr,int tw); }; CCar::CCar(int p,int tr,int w):price(p),tyre(tr,w) { }; int main() { CCar car(20000,17,225); return 0; } 任何对象初始化时都会引发构造函数的调用 att.如果CCar类不定义构造函数则 CCar car 会出错 因为编译器不明白car.tyre该如何初始化,car.enginr的初始化没有问题,用默认构造函数即可 任何生成封闭类对象的额语句,都要让编译器明白

C++拷贝构造函数和拷贝赋值运算符问题

こ雲淡風輕ζ 提交于 2020-02-07 16:05:27
为什么需要析构函数就几乎需要拷贝构造函数和拷贝赋值运算符?或者说拷贝构造函数和拷贝赋值运算符什么时候需要自己构造? 答: 当类内出现指针时,为了防止浅拷贝,即只对指针变量进行拷贝,而不对指针指向的对象也进行复制。自定义拷贝构造函数是为了防止析构函数多次delete同一个指针对象,而自定义拷贝赋值运算符是为了防止在赋值后一个指针所指向对象改变值后不改变另一个指针对象的值。 需要自定义拷贝构造函数示例(可注释掉拷贝构造函数,看注释前后输出发生了什么变化) // // Created by raysuner on 20-2-2. // #include <iostream> using namespace std; class A{ private: string *str; public: explicit A(const string &s){ cout << "构造函数" << endl; str = new string(s); } A(const A &a){ cout << "拷贝构造函数" << endl; this->str = new string(*a.str); } ~A() {delete str; cout << "析构函数" << endl;} void print(){ cout << *(this->str) << endl; } }; A f(A a){