C++热点知识回顾

C++的虚函数表

每个类都有自己的虚函数表,所有对象共用一个;虚函数表指针一般放在实例化内存对象的最前面,并在构造函数执行时初始化。虚函数表存放在只读数据区(gcc)或常量区(微软)

详见:C++ 内存管理

c++ 内存碎片怎么处理:

内存堆栈存储方向,c++堆栈溢出会溢出怎样的数据?内存的大小端如何影响其溢出结果?

c++对象内存分布

c++的内存字节对齐

智能指针与为什么要使用智能指针
shared_ptr
unique_ptr
weak_ptr

智能指针的作用原理就是通过引用计数的方式,在对应的引用计数归0时,自动调用析构函数释放资源。

C++ 11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。

引用计数为0时,智能指针会自动释放引用的内存资源。对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针,因为一个是指针,一个是类。可以通过make_shared函数或者通过构造函数传入普通指针。并可以通过get函数获得普通指针。

智能指针的作用是管理指针,防止对象申请的空间在函数结束时忘记释放。因为智能指针是一个类,当超出了类的实例对象的作用域时,会自动调用对象的析构函数,析构函数会自动释放资源。

unique_ptr 实现指针的独占式拥有,保证同一时间只有一个智能指针可以指向该对象。它对于避免资源泄漏非常有用。

unique_ptr<string> p3 (new string ("auto"));   //#4
unique_ptr<string> p4;                       //#5
p4 = p3;//此时会报错!!

另外unique_ptr还有更聪明的地方:当程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做

unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1;                                      // #1 不允许
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You"));   // #2 允许

如果想安全地重用unique_prt指针,可以通过标准库 std::move(),这个语法旨在强调你在转移指针的所有权,让你清晰的知道自己在做什么,从而不乱调用原有指针。如果转移所有权之后,再调用原有指针程序会崩溃。boost库的boost::scoped_ptr也是一个独占性智能指针,但是它不允许转移所有权,从始而终都只对一个资源负责,它更安全谨慎,但是应用的范围也更狭窄。

详解c++智能指针
c++博客库

C++:多继承中的二义性问题
https://blog.csdn.net/lhc1105/article/details/20154795
https://www.cnblogs.com/kongbursi-2292702937/p/14724793.html

通过虚继承的方式,使得派生类只产生一个子对象

std::cout 是线程不安全的输出,printf 是线程安全的。

常量指针与指针常量:

const int p:
常量指针,表示指向的是常量,指向的内容不可被修改,但是指针可以指向别的常量。(const 修饰 int
表示指向的内容不可以改变);
常量指针经常用在函数传参中,以避免函数内部修改内容。

int* const p:
指针常量,指针不能修改指向,但是指向的值可以改变。(const 修饰变量 p,表示 p 不能指向别的区域)

int& a:
引用必须在定义时初始化,并且以后不能再指向其他数据;

std::vector 内存分配
std::vector<T> vec(3); 临时变量vec 会在栈上分配一个空间,然后另外创建三个空间。

C++工程师常见的面试题总结: https://baijiahao.baidu.com/s?id=1697075603721482782&wfr=spider&for=pc

为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?

将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。

C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。

一个C++源文件从文本到可执行文件经历的过程?

对于C++源文件,从文本到可执行文件一般需要四个过程:

预处理阶段:对源代码文件中文件包含关系(头文件)、预编译语句(宏定义)进行分析和替换,生成预编译文件。

编译阶段:将经过预处理后的预编译文件转换成特定汇编代码,生成汇编文件

汇编阶段:将编译阶段生成的汇编文件转化成机器码,生成可重定位目标文件

链接阶段:将多个目标文件及所需要的库连接成最终的可执行目标文件

new和malloc的区别?

1、new分配内存按照数据类型进行分配,malloc分配内存按照指定的大小分配;

2、new返回的是指定对象的指针,而malloc返回的是void*,因此malloc的返回值一般都需要进行类型转化。

3、new不仅分配一段内存,而且会调用构造函数,malloc不会。

4、new分配的内存要用delete销毁,malloc要用free来销毁;delete销毁的时候会调用对象的析构函数,而free则不会。

5、new是一个操作符可以重载,malloc是一个库函数。

6、malloc分配的内存不够的时候,可以用realloc扩容。扩容的原理?new没用这样操作。

7、new如果分配失败了会抛出bad_malloc的异常,而malloc失败了会返回NULL。

8、申请数组时: new[]一次分配所有内存,多次调用构造函数,搭配使用delete[],delete[]多次调用析构函数,销毁数组中的每个对象。而malloc则只能sizeof(int) * n。

C++ 热加载
一般是通过冲加载.so文件实现热更替。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 using1174@foxmail.com

文章标题: C++热点知识回顾

文章字数: 1,660

本文作者: Jun

发布时间: 2022-03-14, 15:20:00

最后更新: 2022-04-17, 22:49:42

原始链接: http://yoursite.com/2022/03/14/C-热点知识回顾/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏