C++一天来几问

Posted 不懂程序懂个球

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++一天来几问相关的知识,希望对你有一定的参考价值。

1、指针和const的用法

1)  当const修饰指针时,由于const的位置不同,它的修饰对象会有所不同。

底层指针表示指针所指向的变量是一个常量。

2、形参与实参的区别?

1)  形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。

2)  实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值,会产生一个临时变量。

3)  实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。

4)  函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。

5)  当形参和实参不是指针类型时,在该函数运行时,形参和实参是不同的变量,他们在内存中位于不同的位置,形参将实参的内容复制一份,在该函数运行结束的时候形参被释放,而实参内容不会改变。

3、值传递、指针传递、引用传递的区别和效率

1)  值传递:有一个形参向函数所属的栈拷贝数据的过程,如果值传递的对象是类对象  或是大的结构体对象,将耗费一定的时间和空间。(传值)

4)  效率上讲,指针传递和引用传递比值传递效率高。一般主张使用引用传递,代码逻辑上更加紧凑、清晰。

4、什么是类的继承?

1) 类与类之间的关系

has-A包含关系,用以描述一个类由多个部件类构成,实现has-A关系用类的成员属性表示,即一个类的成员属性是另一个已经定义好的类;

use-A,一个类使用另一个类,通过类之间的成员函数相互联系,定义友元或者通过传递参数的方式来实现;

is-A,继承关系,关系具有传递性;

2) 继承的相关概念

所谓的继承就是一个类继承了另一个类的属性和方法,这个新的类包含了上一个类的属性和方法,被称为子类或者派生类,被继承的类称为父类或者基类;

3) 继承的特点

子类拥有父类的所有属性和方法,子类可以拥有父类没有的属性和方法,子类对象可以当做父类对象使用;

4) 继承中的访问控制

public、protected、private

5) 继承中的构造和析构函数

6) 继承中的兼容性原则

5、什么是内存池,如何实现

内存池(Memory Pool) 是一种内存分配方式。通常我们习惯直接使用new、malloc 等申请内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块, 若内存块不够再继续申请新的内存。这样做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升。

这里简单描述一下《STL源码剖析》中的内存池实现机制:

allocate包装malloc,deallocate包装free

一般是一次20*2个的申请,先用一半,留着一半,为什么也没个说法,侯捷在STL那边书里说好像是C++委员会成员认为20是个比较好的数字,既不大也不小

  1. 首先客户端会调用malloc()配置一定数量的区块(固定大小的内存块,通常为8的倍数),假设40个32bytes的区块,其中20个区块(一半)给程序实际使用,1个区块交出,另外19个处于维护状态。剩余20个(一半)留给内存池,此时一共有(20*32byte)

  2. 客户端之后有有内存需求,想申请(20*64bytes)的空间,这时内存池只有(20*32bytes),就先将(10*64bytes)个区块返回,1个区块交出,另外9个处于维护状态,此时内存池空空如也

  3. 接下来如果客户端还有内存需求,就必须再调用malloc()配置空间,此时新申请的区块数量会增加一个随着配置次数越来越大的附加量,同样一半提供程序使用,另一半留给内存池。申请内存的时候用永远是先看内存池有无剩余,有的话就用上,然后挂在0-15号某一条链表上,要不然就重新申请。

  4. 如果整个堆的空间都不够了,就会在原先已经分配区块中寻找能满足当前需求的区块数量,能满足就返回,不能满足就向客户端报bad_alloc异常

《STL源码解析》侯捷 P68

allocator就是用来分配内存的,最重要的两个函数是allocate和deallocate,就是用来申请内存和回收内存的,外部(一般指容器)调用的时候只需要知道这些就够了。内部实现,目前的所有编译器都是直接调用的::operator new()和::operator delete(),说白了就是和直接使用new运算符的效果是一样的,所以老师说它们都没做任何特殊处理。

最开始GC2.9之前:

new和 operator new 的区别:new 是个运算符,编辑器会调用 operator new(0)

operator new()里面有调用malloc的操作,那同样的 operator delete()里面有调用的free的操作

GC2.9的alloc的一个比较好的分配器的实现规则

维护一条0-15号的一共16条链表,其中0表示8 bytes ,1表示 16 bytes,2表示 24bytes。。。。而15 表示 16* 8 = 128bytes,如果在申请时并不是8的倍数,那就找刚好能满足内存大小的那个位置。比如想申请 12,那就是找16了,想申请 20 ,那就找 24 了

但是现在GC4.9及其之后 也还有,变成pool_alloc这个名字了,不再是默认的了,你需要自己去指定它可以自己指定,比如说vector<string,_gnu_cxx::pool_alloc> vec;这样来使用它,现在用的又回到以前那种对malloc和free的包装形式了

6、从汇编层去解释一下引用

9:      int x = 1;

00401048 mov     dword ptr [ebp-4],1

10:     int &b = x;

0040104F   lea     eax,[ebp-4]

00401052 mov     dword ptr [ebp-8],eax

7、深拷贝与浅拷贝是怎么回事?

2)  在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

8、C++模板是什么,你知道底层怎么实现的?

1)  编译器并不是把函数模板处理成能够处理任意类的函数;编译器从函数模板通过具体类型产生不同的函数;编译器会对函数模板进行两次编译:在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。

2)  这是因为函数模板要被实例化后才能成为真正的函数,在使用函数模板的源文件中包含函数模板的头文件,如果该头文件中只有声明,没有定义,那编译器无法实例化该模板,最终导致链接错误。

9、new和malloc的区别?

1、 new/delete是C++关键字,需要编译器支持。malloc/free是库函数,需要头文件支持;

2、 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。

3、 new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。

4、 new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。

5、 new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。

10、delete p、delete [] p、allocator都有什么作用?

1、 动态数组管理new一个数组时,[]中必须是一个整数,但是不一定是常量整数,普通数组必须是一个常量整数;

2、 new动态数组返回的并不是数组类型,而是一个元素类型的指针;

3、 delete[]时,数组中的元素按逆序的顺序进行销毁;

4、 new在内存分配上面有一些局限性,new的机制是将内存分配和对象构造组合在一起,同样的,delete也是将对象析构和内存释放组合在一起的。allocator将这两部分分开进行,allocator申请一部分内存,不进行初始化对象,只有当需要的时候才进行初始化操作。




以上是关于C++一天来几问的主要内容,如果未能解决你的问题,请参考以下文章

[LCA]二月的最后一天来搞事情吧

第一天来公司拉取的代码pom内的parent依赖不上是啥原因?

这些 C++ 代码片段有啥作用?

有趣的 C++ 代码片段,有啥解释吗? [复制]

以下代码片段 C++ 的说明

C++ 代码片段执行