栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++面试基础知识

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++面试基础知识

1. 变量的声明和定义

变量的定义为变量分配地址和存储空间,变量的声明不分配地址。一个变量可以在多个地方声明,但是只在一个地方定义。

2. C++的特点是什么

保留了C语言原有的优点,与C语言兼容;增加了面向对象的机制“类class”,类(calss)为C++重要的数据类型,可以实现面向对象时进行封装、信息隐蔽、继承、派生、多态等;使用C++命名空间std;C++新标准中,使用不带后缀“.h”的头文件,但兼容C语言的头文件;

3. C++的异常处理机制

传统错误处理机制:通过函数返回值来处理错误。
C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计对不同类型异常的处理。

4. C和C++,java的区别

C语言面向过程, C++语言是面向对象加过程语言, java是纯面向对象的,没有指针的概念

5. C++ 11 nullptr 和 NULL

NULL: 预处理变量,是一个宏,它的值是0,定义在头文件中,即#define NULL 0。
nullptr: C++ 11 中的关键字,是一种特殊类型的字面值,可以被转换成任意其他类型。

6. #ifdef、#else、#endif和#ifndef的作用

利用#ifdef、#endif将某程序功能模块包括进去,以向特定用户提供该功能。在不需要时用户可轻易将其屏蔽。

7. C 语言的关键字 static 和 C++ 的关键字static有什么区别

在 C 中 static 用来修饰局部静态变量和外部静态变量、函数。而 C++中除了上述功能外,还用来定义类的成员变量和函数。即静态成员和静态成员函数。
**注意:**编程时 static 的记忆性,和全局性的特点可以让在不同时期调用的函数进行通信,传递信息,而 C++的静态成员则可以在多个对象实例间进行通信,传递信息。

8. c++和c中字符串区别

C语言中没有字符串这个数据类型,而是用了字符数组,也就是它是char 型的数组。null字符结尾的字符数组才是C字符串,否则只是一般的C字符数组。
C++中有字符串数据类型string,可以直接声明变量并进行赋值等字符串操作

9. Implicit,explicit关键字

explicit关键字只能用于修饰只有一个参数的类构造函数,表明该构造函数是显示的, implicit, 意思是隐藏的, 类构造函数默认情况下即声明为implicit(隐式).隐式转换可以通过消除不必要的类型转换来提高源代码的可读性

10. mutable关键字

在 C++ 中,mutable 是为了突破 const 的限制而设置的。被 mutable 修饰的变量,将永远处于可变的状态,即使在一个 const 函数中,甚至结构体变量或者类对象为 const,其 mutable 成员也可以被修改。
const 关键字,用于常成员函数,即“不允许在常成员函数内部修改对象状态的值。”
mutable 关键字,用于常成员函数,即“允许修改常成员函数内部不是对象状态的值。”

11. volatile关键字

保证内存可见性: volatile可见性是通过汇编加上Lock前缀指令,触发底层的MESI缓存一致性协议来实现的。
保证内存有序性: 禁止指令重排序,指令的执行顺序并不一定会像我们编写的顺序那样执行,为了保证执行上的效率,JVM(包括CPU)可能会对指令进行重排序。 volatile有序性是通过内存屏障实现的。JVM和CPU都会对指令做重排优化,所以在指令间插入一个屏障点,就告诉JVM和CPU,不能进行重排优化。
不保证原子性: 尽管volatile关键字可以保证内存可见性和有序性,但不能保证原子性。也就是说,对volatile修饰的变量进行的操作,不保证多线程安全。

12. 类的大小,空类

与类大小有关的因素:普通成员变量,虚函数,继承(单一继承,多重继承,重复继承,虚拟继承)
与类大小无关的因素:静态成员变量,静态成员函数及普通成员函数
空类即什么都没有的类,按上面的说法,照理说大小应该是0,但是,空类的大小为1,因为空类可以实例化,实例化必然在内存中占有一个位置,因此,编译器为其优化为一个字节大小。

13. void*、多重指针及其大小

所有类型指针大小都为4
用void* 定义一个void类型的指针,它不指向任何类型的数据,,它属于一种未确定类型的过渡型数据,因此如果要访问实际存在的数据,必须将void指针强转成为指定一个确定的数据类型的数据,如int、string等。void指针只支持几种有限的操作:与另一个指针进行比较;向函数传递void指针或从函数返回void指针;给另一个void指针赋值。:void只提供一个地址,没有指向。
**相当于指向指针的指针,本质还是一个指针,只是它指向的是一个地址。&很简单,即同级运算,从右到左,先进行地址&运算再进行指针运算。

14. 简述类成员函数的重写、重载和隐藏的区别

重载的定义为:在同一作用域中,同名函数的形式参数(参数个数、类型或者顺序)不同时,构成函数重载。
隐藏定义:指不同作用域中定义的同名函数构成隐藏(不要求函数返回值和函数参数类型相同)。比如派生类成员函数隐藏与其同名的基类成员函数、类成员函数隐藏全局外部函数。
重写/覆盖的定义:派生类中与基类同返回值类型、同名和同参数的虚函数重定义,构成虚函数覆盖,也叫虚函数重写。
重写与重载主要有以下不同:
(1)范围的区别:被重写的和重写的函数在两个类中,而重载和被重载的函数在同一个类中;
(2)参数的区别:被重写函数和重写函数的参数列表一定相同,而被重载函数和重载函数的参数列表一定不同;
(3)virtual的区别:重写的基类中被重写的函数必须要有virtual修饰,而重载函数和被重载函数可以被virtual修饰,也可以没有
隐藏和重写,重载有以下不同:
(1)与重载的范围不同:和重写一样,隐藏函数和被隐藏函数不在同一个类中;
(2)参数的区别:隐藏函数和被隐藏的函数的参数列表可以相同也可以不同,但是函数名肯定要相同。当参数不同时,无论基类的参数是否被virtual修饰,基类的函数都是被隐藏,而不是被重写。
虽然重载和覆盖都是实现多态的基础,但是两者实现的技术完全不相同,达到的目的也是完全不同的。覆盖是动态绑定的多态,重载是静态绑定的多态。

15. final和override说明符

在写虚函数时,想让派生类中的虚函数覆盖掉基类虚函数,有时我们会不小心写错,造成了隐藏,这不是我们想要看到的结果。所以C++ 11新标准中我们可以使用override关键字来说明派生类中的虚函数。
如果使用override标记了某个函数,但该函数并没有覆盖已存在的虚函数,此时编译器将报错。使用override是希望能覆盖基类中的虚函数,如果不符合则编译器报错。
把某个函数指点为 final ,意味着任何尝试覆盖该函数的操作都将引发错误,final 和 override 说明符出现在形参列表以及尾置返回类型之后。final 还可以跟在类的后面,意思这个类不能当做其它类的基类。

16. 封装继承多态

封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!
封装可以隐藏实现细节,使得代码模块化;封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。在面向对象编程上可理解为:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。其继承的过程,就是从一般到特殊的过程。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承概念的实现方式有三类:实现继承、接口继承和可视继承:
1)实现继承是指使用基类的属性和方法而无需额外编码的能力;
2)接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
3) 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。
**多态性(polymorphisn)**是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
实现多态,有二种方式,覆盖,重载。**覆盖:**是指子类重新定义父类的虚函数的做法。**重载:**是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

17. 静态多态和动态多态

多态性可以简单地概括为**“一个接口,多种方法”**。
**静态多态:**也称为编译期间的多态,编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。
静态多态有两种实现方式:
**函数重载:**包括普通函数的重载和成员函数的重载
函数模板的使用
**动态多态(动态绑定):**即运行时的多态,在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方法,是用虚函数机制实现的。
不同点:
1、本质不同,静态多态在编译期决定,由模板具现完成,而动态多态在运行期决定,由继承、虚函数实现;
2、动态多态中接口是显式的,以函数签名为中心,多态通过虚函数在运行期实现,静态多台中接口是隐式的,以有效表达式为中心,多态通过模板具现在编译期完成

18. 虚函数原理及实现(虚函数表+虚函数指针)

C++中的虚函数的作用主要是实现了多态的机制。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。
虚函数的实现是由两个部分组成的,虚函数指针与虚函数表。
虚函数指针从本质上来说就只是一个指向函数的指针,与普通的指针并无区别。它指向用户所定义的虚函数,具体是在子类里的实现,当子类调用虚函数的时候,实际上是通过调用该虚函数指针从而找到接口。只有拥有虚函数的类才会拥有虚函数指针,每一个虚函数也都会对应一个虚函数指针。所以拥有虚函数的类的所有对象都会因为虚函数产生额外的开销,并且也会在一定程度上降低程序速度。
在虚函数表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
C++中一个类是公用一张虚函数表的,基类有基类的虚函数表,子类是子类的虚函数表,这极大的节省了内存

19. 虚函数和纯虚函数

定义一个函数为虚函数,不代表函数为不被实现的函数。
定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
定义一个函数为纯虚函数,才代表函数没有被实现
定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。

20. C 语言的 malloc 和 C++ 中的 new 有什么区别

属性: new和delete是C++关键字,需要编译器支持;malloc和free是库函数,需要头文件支持。
参数: 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。
返回类型: new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。
自定义类型: new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。
malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
“重载”: C++允许自定义operator new 和 operator delete 函数控制动态内存的分配。
内存区域: new做两件事:分配内存和调用类的构造函数,delete是:调用类的析构函数和释放内存。而malloc和free只是分配和释放内存。
new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆,如上所述,布局new就可以不位于堆中。
分配失败: new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。
内存泄漏:内存泄漏对于new和malloc都能检测出来,而new可以指明是哪个文件的哪一行,malloc确不可以。

21. c++ 析构函数调用时间

对象生命周期结束被销毁时。
delete指向对象的指针时,或者delete指向对象的基类类型的指针,而基类析构函数是虚函数。
对象A是对象B的成员,B的析构函数被调用时,对象A的析构函数也会被调用。

22. 简述C、C++程序编译的内存分配情况

一个C,C++程序编译时内存分为5大存储区:堆区,栈区,全局区,文字常量区,程序代码区。
C,C++中内存分配方式可以分为三种:
(1)从静态存储区域分配:
内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量等。
(2)在栈上分配:
在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配:
即动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用灵活。
当在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏。其次频繁地分配和释放不同大小的对空间将会产生堆

23. malloc、vmalloc、kmalloc区别

(1)kmalloc和vmalloc是分配内核的内存,malloc分配的是用户空间的内存。
(2)kmalloc 保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc申请的内存不一定连续(用户空间存储以空间链表的方式组织(地址递增),每一个链表块包含一个长度、一个指向下一个链表块的指针以及一个指向自身的存储空间指针。)
(3)kmalloc能分配的大小有限,vmalloc与malloc能分配的空间大小相对较大。
(4)内存只有在要被DMA访问的时候才需要物理上连续。
(5)vmalloc要不kmalloc要慢。

24. 什么是内存泄漏,如何避免

用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(就是该内存空间使用完毕之后未回收)即所谓内存泄漏。

常见的内存泄露:
1.指针重新赋值;
2.错误的内存释放;
3.返回值的不正确处理。

如何避免:
1.确保没有在访问空指针;
2.每个内存分配函数都应该有一个 free 函数与之对应,alloca 函数除外;
3.每次分配内存之后都应该及时进行初始化,可以结合 memset 函数进行初始化,calloc 函数除外;
4.每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对;
5.在对指针赋值前,一定要确保没有内存位置会变为孤立的;
6.每当释放结构化的元素(而该元素又包含指向动态分配的内存位置的指针)时,都应先遍历子内存位置并从那里开始释放,然后再遍历回父节点;7.始终正确处理返回动态分配的内存引用的函数返回值。

25. 介绍一下申请内存

malloc(unsigned int n) 在堆上申请内存,其原理是维护一个内存空闲链表,分配时给你一个空闲大小和申请大小最接近的地址,当然,返回的是不确定类型的指针void*,需要转换位确定类型指针,如果没有空闲内存,则返回空指针。该函数调用后需要手动调用free函数释放内存,不然会造成内存泄漏,另外频繁调用该方法获取大小不一的内存会造成内存零散化。
calloc(n,s) 申请n份大小为s的内存,并且会初始化这部分内存,感觉比malloc()高级些,这个内存申请后应该也要手动释放。
realloc(m,new_size) 是找一块new_size大小的内存,然后把m内容拷贝过去,返回新内存地址,但如果原来地址后面有足够的内存,好像是直接扩展就行。
_alloc() 就是编译器自动调用的内存申请函数,自动释放内存,不需要手动释放。

26. 追问内存溢出、内存泄漏

内存溢出:(out of memory) 通俗理解就是内存不够,指程序要求的内存超出了系统所能分配的范围,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。比如申请一个int类型,但给了它一个int才能存放的数,就会出现内存溢出,或者是创建一个大的对象,而堆内存放不下这个对象,这也是内存溢出。
内存泄漏:(Memory Leak) 是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
内存泄露可能会导致内存溢出。
内存溢出会抛出异常,内存泄露不会抛出异常,大多数时候程序看起来是正常运行的。

27. 内存分区

在C/C++中对于内存分区来说,可以划分为四大内存分区。他们分别是堆、栈、全局/静态存储区和代码区。
1.堆区:
由编程人员手动申请,手动释放,若不手动释放,程序结束后由系统回收,生命周期是整个程序运行期间.使用malloc或者new进行堆的申请,堆的总大小为机器的虚拟内存的大小。
new操作符本质上是使用了malloc进行内存的申请,new和malloc的区别如下:   
(1)malloc是C语言中的函数,而new是C++中的操作符。   
(2)malloc申请之后返回的类型是void*,而new返回的指针带有类型。   
(3)malloc只负责内存的分配而不会调用类的构造函数,而new不仅会分配内存,而且会自动调用类的构造函数。
2.栈区:
由系统进行内存的管理。主要存放函数的参数以及局部变量。在函数完成执行,系统自行释放栈区内存,不需要用户管理。整个程序的栈区的大小可以在编译器中由用户自行设定,VS中默认的栈区大小为1M,可通过VS手动更改栈的大小。
3.全局/静态存储区:
全局/静态存储区内的变量在程序编译阶段已经分配好内存空间并初始化。这块内存在程序的整个运行期间都存在,它主要存放静态变量、全局变量和常量。
(1) 是因为静态存储区内的变量若不显示初始化,则编译器会自动以默认的方式进行初始化,即静态存储区内不存在未初始化的变量。
(2)静态存储区内的常量分为常变量和字符串常量,一经初始化,不可修改。静态存储内的常变量是全局变量,与局部常变量不同,区别在于局部常变量存放于栈,实际可间接通过指针或者引用进行修改,而全局常变量存放于静态常量区则不可以间接修改。   
(3)字符串常量存储在全局/静态存储区的常量区,字符串常量的名称即为它本身,属于常变量。   
(4)数据区的具体划分,有利于我们对于变量类型的理解。不同类型的变量存放的区域不同。
4.代码区:
存放程序体的二进制代码。比如我们写的函数,都是在代码区的。

28. malloc的底层原理

malloc 函数的实质是它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。
调用 malloc()函数时,它沿着连接表寻找一个大到足以满足用户请求所需要的内存块。(如果没有搜索到,那么就会用sbrk()才推进brk指针来申请内存空间)。
然后,将该内存块一分为二(一块的大小与用户申请的大小相等,另一块的大小就是剩下来的字节)。 接下来,将分配给用户的那块内存存储区域传给用户,并将剩下的那块(如果有的话)返回到连接表上。
调用 free 函数时,它将用户释放的内存块连接到空闲链表上。
到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段, 那么空闲链表上可能没有可以满足用户要求的片段了。于是,malloc() 函数请求延时,并开始在空闲链表上检查各内存片段,对它们进行内存整理,将相邻的小空闲块合并成较大的内存块。

29. C语言的指针和c++的引用有什么区别
  1. C++的引用和C语言的指针有以下区别:
    (1)引用必须初始化,但是不分配存储空间。指针不声明时初始化,在初始化的时候需要分配存储空间。引用较比指针更加安全;
    (2)引用指向一块特定的内存,不能被更改。不存在指向空值的引用,但是存在指向空值的指针。指针可指向任意一块内存,可以改变所指的对象;
    (3)指针的大小确定,引用的大小根据所引用的类型确定;
    (4)指针使用时必须解引用;
    (5)定义一个指针和引用在汇编语言中表示相同;
    (6)指针可以多级引用。
30. 句柄和指针的区别和联系是什么

句柄和指针其实是两个截然不同的概念。Windows系统用句柄标记系统资源,隐藏系统的信息。你只要知道有这个东西,然后去调用就行了,它是个32it的uint。指针则标记某个物理内存地址,两者是不同的概念。

31. 静态链接和动态链接

在C语言中,我们知道要生成可执行文件,必须经历两个阶段,即编译、链接。在编译过程中,只有编译,不会涉及到链接。
在链接过程中,静态链接和动态链接就出现了区别。静态链接的过程就已经把要链接的内容已经链接到了生成的可执行文件中,就算你在去把静态库删除也不会影响可执行程序的执行;而动态链接这个过程却没有把内容链接进去,而是在执行的过程中,再去找要链接的内容,生成的可执行文件中并没有要链接的内容,所以当你删除动态库时,可执行程序就不能运行。

32. 智能指针

所谓的智能指针本质就是一个类模板,它可以创建任意的类型的指针对象,当智能指针对象使用完后,对象就会自动调用析构函数去释放该指针所指向的空间。所有的智能指针类模板中都需要包含一个指针对象,构造函数和析构函数。
1)auto_ptr
auto_ptr是c++98版本库中提供的智能指针,该指针解决上诉的问题采取的措施是管理权转移的思想,也就是原对象拷贝给新对象的时候,原对象就会被设置为nullptr,此时就只有新对象指向一块资源空间。 如果auto_ptr调用拷贝构造函数或者赋值重载函数后,如果再去使用原来的对象的话,那么整个程序就会崩溃掉(因为原来的对象被设置为nullptr),这对程序是有很大的伤害的.所以很多公司会禁用auto_ptr智能指针。
⭐auto_ptr以前是用在C98中,C++11被抛弃,头文件一般用来作为独占指针
⭐auto_ptr被赋值或者拷贝后,失去对原指针的管理
⭐auto_ptr不能管理数组指针,因为auto_ptr的内部实现中,析构函数中删除对象使用delete而不是delete[],释放内存的时候仅释放了数组的第一个元素的空间,会造成内存泄漏。
⭐ auto_ptr不能作为容器对象,因为STL容器中的元素经常要支持拷贝,赋值等操作。
2) unique_ptr
unique_ptr是c++11版本库中提供的智能指针,它直接将拷贝构造函数和赋值重载函数给禁用掉,因此,不让其进行拷贝和赋值。
⭐ C++11中用来替代auto_ptr
⭐拷贝构造和赋值运算符被禁用,不能进行拷贝构造和赋值运算
⭐ 虽然禁用了拷贝构造和赋值运算符,但unique_ptr可以作为返回值,用于从某个函数中返回动态申请内存的所有权,本质上是移动拷贝,就是使用std:move()函数,将所有权转移。
3) share_ptr
share_ptr是c++11版本库中的智能指针,shared_ptr允许多个智能指针可以指向同一块资源,并且能够保证共享的资源只会被释放一次,因此是程序不会崩溃掉。
shared_ptr采用的是引用计数原理来实现多个shared_ptr对象之间共享资源:
⭐ 多个指针可以指向相同的对象,调用release()计数-1,计数0时资源释放
⭐ .use_count()查计数
⭐ .reset()放弃内部所有权
⭐ share_ptr多次引用同一数据会导致内存多次释放
⭐ 循环引用会导致死锁,
⭐ 引用计数不是原子操作。
4) weak_ptr
⭐ 解决两个share_ptr互相引用产生死锁,计数永远降不到0,没办法进行资源释放,造成内存泄漏的问题。
⭐ 使用时配合share_ptr使用,把其中一个share_ptr更换为weak_ptr。

33. 什么是野指针和悬空指针?

若指针指向一块内存空间,当这块内存空间被释放后,该指针依然指向这块内存空间,此时,称该指针为“悬空指针”。 “野指针”是指不确定其指向的指针,未初始化的指针为“野指针”。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/982756.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号