1、进程虚拟地址划分:
- 内存分区和编译链接
- C++内存分区(考虑const常量分区)
- 32位操作系统上,3G用户空间+1G内核空间,从低地址到高地址:
.text段->.rodata段->.data段->.bss段->.heap段->.stack段->内核空间
.text段
:存放指令,只读不写.rodata段
:存放字符串常量,只读不写.data段
:初始化的全局变量和静态变量,初始化值不为0.bss段
:未初始化数据的全局变量静态变量,或者是初始化为0的全局变量和静态变量.heap段
:new来的数据.stack段
:函数的局部变量等
- 不同进程用户空间独立,内核空间共享
- .stack段高地址向低地址增长,.heap段低地址向高地址增长,这两个分区段之间加载动态连接库(.so/.dll)
2、函数调用队栈的过程
3、编译连接
- 可执行文件产生的四步:预编译、编译、汇编、连接
- 预编译:
- 编译:
- 汇编:
- 连接:
- 可执行文件:windows(PE头的文件)、Linux(ELF文件)
4、形参带默认参数
5、内联函数
6、函数重载
7、const
8、const和指针
9、指针和引用
10、new和malloc
11、类和对象、this指针
12、析构函数和构造函数
13、深浅拷贝问题
14、继承的本质和原理
C++11汇总:
-
nullptr:nullptr和NULL的区别
- C++中
NULL
宏定义出来的是0
,为了区分0和空指针就有了nullptr - C中NULL宏定义出来的是
(void*)0
- C++中
-
bind绑定器(bind、function、lambda):
- 弥补了bind1st 和 bind2nd的局限(只能作用于二元函数对象),可以将对多元函数对象进行绑定参数,并且还可以作用于普通函数、函数指针、lambda表达式等可以用来调用的实体,用来绑定参数并返回一个新的函数对象,底层的函数类型会随着参数的绑定进行改变;也可以使用占位符(命名空间
placeholders
),不进行参数绑定,最多可以有20个,在实际用到的时候传入参数;
- 弥补了bind1st 和 bind2nd的局限(只能作用于二元函数对象),可以将对多元函数对象进行绑定参数,并且还可以作用于普通函数、函数指针、lambda表达式等可以用来调用的实体,用来绑定参数并返回一个新的函数对象,底层的函数类型会随着参数的绑定进行改变;也可以使用占位符(命名空间
-
function函数对象:
- 是个模板类,可以接收bind返回的函数对象、lambda匿名函数对象、普通函数等一些可以调用的目标实体,相当于是进行函数类型保存并封装,可以类似于函数指针的使用,但是底层调用的也是operator()重载;lambda表达式和bind返回的函数对象都只能作用于当前语句,function就解决了他们的问题,可以保存它们的类型并多次使用;一般是function和配合bind完成回调函数的设置;
-
lambda匿名函数对象:
- 语法是
[中括号捕获外部变量](小括号参数列表)->右箭头返回值类型{花括号函数体}
,底层是编译器实现的匿名函数对象,通过小括号运行符重载实现的,参数列表不带mutale
关键字的话,底层的operator
重载默认是只读属性(const修饰的函数);比函数对象轻量,不用定义类;对外部变量的捕获可以是引用、也可以是值传递;
- 语法是
-
智能指针:不带引用计数的智能指针、带引用计数的智能指针
- 裸指针的使用,容易忘记delete,所以利用栈对象出作用域的特性管理裸指针,防止内存泄露,智能指针底层提供了
->
运算符重载和*
运算符重载,能像正常指针来使用 - auto_ptr:
- 独占式的管理内存资源,永远只有最后一个auto_ptr管理资源
- 底层只有裸指针和普通的拷贝构造和赋值重载,资源的转移,在代码复杂的时候不容易看出来,容易引起编码上的安全问题,使用已经转移资源的空指针;
- unique_ptr:
- 也是独占式的管理内存资源,相比于auto_ptr,删除了普通的拷贝构造和赋值重载,提供右值版本的,可以将资源转移摆在明面上,就是正常的左值必须通过
std::move()
才能进行资源转移,直接传左值编译会报错
- 也是独占式的管理内存资源,相比于auto_ptr,删除了普通的拷贝构造和赋值重载,提供右值版本的,可以将资源转移摆在明面上,就是正常的左值必须通过
- shared_ptr:
- 共享式的管理的内存资源,底层有个内存
资源计数器
,每次拷贝或者赋值的时候,资源加1
,每次有shared_ptr被释放的时候,资源减1
,当资源数为0
的时候,释放资源; - 使用
shared_ptr
时候需要注意不能用裸指针重复赋值,会导致内存资源重复释放,因为资源计数器都不一样了,应该优先使用make_share
比较安全 - 使用get方法获取底层裸指针,要注意资源的安全
- 共享式的管理的内存资源,底层有个内存
- weak_ptr:
- 和share_ptr搭配使用,不改变引用计数,用来观测shared_ptr管理的资源生命周期,没有提供
->
运算符重载和*
运算符重载,如果想使用资源可以通过lock()
方法来将自己提升为shared_ptr
,提升成功的前提是,shared_ptr
管理的资源还存在(use_count>0
);
- 和share_ptr搭配使用,不改变引用计数,用来观测shared_ptr管理的资源生命周期,没有提供
- 循环引用问题:不同的类里面定义了指向对方
shared_ptr
, 彼此相互引用,引用计数增加,导致堆上对象和类里面的智能指针共存
,最后都不能被释放导致资源泄露,可以通过weak_ptr
来解决,weak_ptr
作为资源观测不会改变引用计数; - 自定义删除器问题:用智能指针管理不能正常delete的类型,比如文件句柄socket等,需要自己定义删除器
- 裸指针的使用,容易忘记delete,所以利用栈对象出作用域的特性管理裸指针,防止内存泄露,智能指针底层提供了
-
移动语义
std::move
和完美转发std::forwad
std::move
:std::forwad
: