析构函数

读书笔记《深度探索c++对象模型》(6) - 执行期语意

只谈情不闲聊 提交于 2019-12-01 05:38:45
一、对象的构造与析构 因声明定义一个类对象,若需要构造或析构函数时,其构造函数和析构函数将被编译器插入到代码中的合适位置,然而因为需要对析构函数的正确且合理的位置调用,可能会出现多个可能的位置插入析构函数的调用代码,如不同处的 return , goto 语句、 {}代码段结束位置等复杂场景中,故建议定义一个类对象时最好放置在需要使用的地方且防止可能在多处插入析构函数的情况,如可用{}早点儿结束析构操作,即最好不要将类对象声明定义在最开始处。 全局对象, C++ 全局对象均放置在数据段中,且被初始化为给定的初值或默认值为 0 ;故而一般情况下全局对象在进入 main 函数前已被初始化,而 main 函数结束时把其析构释放掉;故而需要编译器提供必要的静态初始化的支持,即全局对象的静态初始化以及对应的析构释放。 全局对象应需要被静态初始化,其不能被放置在 try 区段内,对静态调用的构造函数可能会抛异常时将引发 terminate 函数调用;另外便是需要控制跨模块做静态初始化的对象的依赖顺序产生的问题和复杂度,建议不要用需要做静态初始化的全局对象。 局部静态对象,需要保证其所在函数被调用多次时,始终仅调用一次构造函数和析构函数,需要编译器来支持实现,插入必要的初始化一次和析构一次的临时保护代码,不同编译器有不同的实现方式(可能通过插入另外一个全局静态的一个对象

智能指针原理及实现(1)shared_ptr

人盡茶涼 提交于 2019-12-01 02:19:55
智能指针原理及实现(1)shared_ptr 0、异常安全 C++没有内存回收机制,每次程序员new出来的对象需要手动delete,流程复杂时可能会漏掉delete,导致内存泄漏。于是C++引入智能指针,可用于动态资源管理,资源即对象的管理策略。 使用 raw pointer 管理动态内存时,经常会遇到这样的问题: 忘记 delete 内存,造成内存泄露。 出现异常时,不会执行 delete ,造成内存泄露。 下面的代码解释了,当一个操作发生异常时,会导致 delete 不会被执行: 1 void func() 2 { 3 auto ptr = new Widget; 4 // 执行一个会抛出异常的操作 5 func_throw_exception(); 6 7 delete ptr; 8 } 在C++98中,为了写出异常安全的代码,代码经常写的很笨拙,如下: 1 void func() 2 { 3 auto ptr = new Widget; 4 try { 5 func_throw_exception(); 6 } 7 catch(...) { 8 delete ptr; 9 throw; 10 } 11 delete ptr; 12 } 使用智能指针能轻易写出异常安全的代码,因为当对象退出作用域时,智能指针将自动调用对象的析构函数,避免内存泄露。 一、智能指针 shared

构造函数私有(单例)

穿精又带淫゛_ 提交于 2019-11-30 22:47:59
很多情况下要求当前的程序中只有一个object。例如一个程序只有一个和数据库的连接,只有一个鼠标的object。通常我们都将构造函数的声明置于public区段,假如我们将 其放入private区段中会发生什么样的后果?这意味着什么?   当我们在程序中声明一个对象时,编译器为调用构造函数(如果有的话),而这个调用将通常是外部的,也就是说它不属于class对象本身的调用,假如构造函数是私有的, 由于在class外部不允许访问私有成员,所以这将导致编译出错。   然而,对于class本身,可以利用它的static公有成员,因为它们独立于class对象之外,不必产生对象也可以使用它们。   此时因为构造函数被class私有化,所以我们要创建出对象,就必须能够访问到class的私有域;这一点只有class的成员可以做得到;但在我们建构 出其对象之前,怎么能利用它的成员呢?static公有成员,它是独立于class对象而存在的,“我们”可以访问得到。假如在某个static函数中创 建了该class的对象,并以引用或者指针的形式将其返回(这里不以对象返回,主要是构造函数是私有的,外部不能创建临时对象),就获得了这个对象的使用权。   下面是例子: class OnlyHeapClass { public: static OnlyHeapClass* GetInstance() { //

整理

牧云@^-^@ 提交于 2019-11-30 19:52:48
C++11 知识整理 对class的理解 答:首先,class 也是一种数据类型,只不过是可以由开发者自由定义的一种数据类型;可以用来封装成员变量和成员函数;支持抽象,继承,多态性;在定义数据类型的时候,private,public,也从一定程度上保证了数据的安全性 抽象性:含有纯虚函数的类被称为抽象类,用途是为派生类提供基类 多态性:对于不同对象接受相同信息时产生不同的动作。分为静态多态和动态多态,体现在两个方面,一是在编译的时候,函数重载是一个方面;二是在运行的时候,虚函数是一个方面 继承性:子类具有父类的各种属性和方法,而不必再次编写相同的代码 什么是类 答:一种将抽象转换成用于定义的类型的工具,将数据表示方法和操纵这些数据的方法组合一起整合成一个包 如何将私有成员变量取出 答:方法1:通过public中的函数,传出参数将私有成员变量取出。方法2:友元函数 *this 指针 答:经典回答,进入一个房间,能看见房间里的东西,但是整个房间看不到了,然后this指针就是时刻盯着这整个房间。this指针是类的一个自动生成,自动隐藏的私有成员。存在于类的非静态成员函数中,指向内调用函数所在的对象。全局仅有一个this指针,当一个对象被创建的时候,this指针就存放指向对象数据的首地址 类和对象的区别和联系 答:区别:(1).定义不同 ,类是现实世界或思维世界的实体在计算机的反映

构造函数调用规则

让人想犯罪 __ 提交于 2019-11-30 15:52:36
首先我们知道只要创建一个类编译器会提供三个默认函数 1.默认构造函数 (无参,空实现) 2.默认析构函数(无参,空实现) 3.默认拷贝构造函数,对值属性进行拷贝 调用规则如下 1.如果我们定义有参构造函数,编译器不会提供默认构造函数,但提供默认拷贝构造函数 2.如果用户定义了拷贝构造函数,编译器将不会提供其他构造函数 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 class person 5 { 6 public: 7 person() 8 { 9 puts("默认构造函数调用"); 10 } 11 12 person(const person &p) 13 { 14 m_age = p.m_age; 15 puts("拷贝构造函数调用"); 16 } 17 18 person(int age) 19 { 20 m_age = age; 21 puts("有参构造函数调用"); 22 } 23 24 ~person() 25 { 26 puts("析构函数调用"); 27 } 28 29 int m_age; 30 }; 31 32 void test() 33 { 34 person p; 35 p.m_age = 18; 36 person p2(p); 37 cout << p2.m_age << endl; 38

牛客 C++刷题day23

荒凉一梦 提交于 2019-11-30 12:46:56
1.C++或者C里面的注释有两种,一种是/*------*/,另外一种是单独一行//----- 即可 2.析构函数名与类名相同,只是在函数名前面加一个位取反符~,以区别于构造函数 。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载 。如果用户没有编写析构函数,编译器 自动生成一个缺省的析构函数(即使自定义了析构函数,编译器 也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。 3. 仿函数的主要功能是为了搭配STL算法使用,单独使用仿函数的情况比较少。 仿函数(functors)在C++标准中采用的名称是函数对象(function objects)。仿函数主要用于STL中的算法中,虽然函数指针虽然也可以作为算法的参数,但是函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求–函数指针无法和STL其他组件搭配,产生更灵活变化。仿函数本质就是类重载了一个operator(),创建一个行为类似函数的对象。 对于重载了()操作符的类,可以实现类似函数调用的过程,所以叫做仿函数,实际上仿函数对象仅仅占用1字节,因为内部没有数据成员,仅仅是一个重载的方法而已。实际上可以通过传递函数指针实现类似的功能

C#中对象的销毁有三种方式Finalize,Dispose,GC。

北城以北 提交于 2019-11-30 12:17:51
1、Finalize方法(C#中是析构函数,以下称析构函数)是用于释放非托管资源的,而托管资源会由GC自动回收。所以,我们也可以这样来区分托管和非托管资源。所有会由GC自动回收的资源,就是托管的资源,而不能由GC自动回收的资源,就是非托管资源。在我们的类中直接使用非托管资源的情况很少,所以基本上不用我们写析构函数。 2、大部分的非托管资源会给系统带来很多负面影响,例如数据库连接不被释放就可能导致连接池中的可用数据库连接用尽。文件不关闭会导致其它进程无法读写这个文件等等。 实现模型: 1、由于大多数的非托管资源都要求可以手动释放,所以,我们应该专门为释放非托管资源公开一个方法。实现IDispose接口的Dispose方法是最好的模型,因为C#支持using语句快,可以在离开语句块时自动调用Dispose方法。 2、虽然可以手动释放非托管资源,我们仍然要在析构函数中释放非托管资源,这样才是安全的应用程序。否则如果因为程序员的疏忽忘记了手动释放非托管资源,那么就会带来灾难性的后果。所以说在析构函数中释放非托管资源,是一种补救的措施,至少对于大多数类来说是如此。 3、由于析构函数的调用将导致GC对对象回收的效率降低,所以如果已经完成了析构函数该干的事情(例如释放非托管资源),就应当使用SuppressFinalize方法告诉GC不需要再执行某个对象的析构函数。 4

构造函数和析构函数

别来无恙 提交于 2019-11-30 12:05:09
C++为什么要有构造函数和析构函数? 传送门: https://blog.csdn.net/u013565071/article/details/78267440 先说一下生活中的场景,大家买的各种电子设备,是不是有个叫出厂设置,就是根据需要给这些设备初始化,进行一些设置 比如时间你得是你那个地方的吧,是美国就不合理了。 同时,当这些设备你不用的时候,你可以买个别人,但是不可能就直接给别人了,你里面可能有些东西,你不想让别人知道 你就必须把你设备里的数据清理掉,不然就像那个香港修电脑哪个^_^ 那么c++对象的初始化和清理是两个很重要的安全问题 对象未初始化,你用的时候结果是未知的 同时用完不清理,也会造成安全问题,比如内存泄露什么的 c++中提供了构造函数和析构函数来解决上述两个问题 构造函格式 类名() 没有返回类型,void也不需要 可以由参数,可以重载 析构函数格式 ~类名() 没有返回类型,void也不需要 不可以有参数,不可以发生重载 这两个函数,都是由系统自动调用,不需要认为调用。而且你可以不写,编译器会帮你写,但是里面的实现是空实现 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 class stu 5 { 6 public: 7 stu() 8 { 9 puts("stu构造函数调用"); 10 } 11

嵌入式C++测试题

早过忘川 提交于 2019-11-30 10:30:18
仅供学习,为嵌入式帝国做亿分之一的贡献吧,临近国庆,祝大家国庆节快乐哦 答案仅供参考吧 一、 选择题(共 80 分, 每题 2 分 ) ( 1 ) A ( 2 ) C ( 3 ) C ( 4 ) B ( 5 ) D ( 6 ) C ( 7 ) C ( 8 ) D ( 9 ) A ( 10 ) C ( 11 ) A (12) B (13) D (14) B (15) A ( 16 ) A ( 17 ) C ( 18 ) D ( 19 ) D ( 20 ) C ( 21 ) C ( 22 ) D ( 23 ) D ( 24 ) D ( 25 ) A ( 26 ) C (27) C (28) C (29) B (30) B ( 31 ) A ( 32 ) D ( 33 ) D ( 34 ) B ( 35 ) A ( 36 ) A ( 37 ) B ( 38 ) B ( 39 ) C ( 40 ) C 二、 填空题(每空 1 分, 共 20 分) 1. 构造函数 2. friend 保护和私有成员 3. 先基类在派生类 4. 单一继承 5. virtual 6. 静态多态性 动态多态性 7. 抽象类 8. 测试是否文件尾 9. 成员函数 10. try throw catch 11. 代码复用和泛型程序设计 12. 类的友元函数 13. 抛出异常 捕捉异常 14. template 15.

浅谈c++ new、delete与malloc和free

纵然是瞬间 提交于 2019-11-30 09:53:47
  malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行 构造函数 和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。 malloc与new:   malloc是c语言的库函数,其作用是在内存中开辟一块连续的指定大小的内存空间(注意:调用malloc必须要指定开辟的空间大小),返回指向该被分配内存的指针(该指针为void * ,需要通过强制类型转换将void*指针转换成我们需要的类型)。 //用例 int* ptr = (int*) malloc (sizeof(int)) //分配一个int类型大小的空间 float* ptr2 = (float*) malloc (sizeof(int)) //分配float类型大小空间 一般情况下 malloc总是能成功分配一块连续的内存空间,但当内存耗尽或者内存过于碎片化而不足以开辟固定大小的连续空间的时候