资源管理和对象的基本原则
C++的特点与演化
- 为什么要使用C++?
- 贴近硬件:
- 使用原生的指令和类型,高性能
- 方便使用硬件(GPU、FPGA等)
- 零开销抽象
- 类、继承、模板
- 零开销!=无开销, 零开销=无额外开销
- 贴近硬件:
- C和C++
- 功能上,C++是C的超集
- C++更加严格和安全,比如说const的正确性、指针的自动转换
- 现代C++的惯用法和C大相径庭
- C和机器码有更简单的映射关系,从C源码可以大致知道机器码是什么样
- C++里有更多的抽象机制,源代码和机器码映射复杂得多
资源管理和对象的基本原则
1. 堆与栈
栈的示例
main对应的x86汇编代码(msvc)
- 设置栈框架:保存原有的ebp的值,设置新的ebp的值,ebp的作用:索引这个函数所用到的参数和本地变量
- 参数压栈
- call:调用bar函数,名字奇怪的原因:编译器会起名
- 退栈:esp的指针+4——
pop eax
:取出数据,ESP指向栈中下一个元素 - 异或操作对eax寄存器清零,函数返回值存储在eax寄存器
bar对应的x86汇编代码(msvc)
调用过程中的栈变化
“返回main的地址”:main下一句指令的地址
栈内存的特性:
- 分配简单,只是移动栈指针
- 当前函数执行完即自动释放
- 后进先出,不可能出现内存碎片
- 函数返回后,栈上对象即被销毁
- 栈内存不分享,栈上对象通常没有多线程竞争问题(除非把指向栈内存的指针传递给另一个线程)
堆内存的特性:
- 分配和释放算法较为复杂
- 可能出现内存碎片
- 内存的分配和释放通常需要加锁
- 堆上的对象在被释放之前一直可以使用
- 堆上对象可能被多个线程访问,潜在有线程竞争问题
2. RAII
——析构函数和RAII是C++最基本的惯用法
RAII:Resource Acquisition Is Initialization
帮助管理堆上的对象:对象很大、对象的大小在编译时不能确定、对象是函数的返回值但由于特殊的原因不应使用对象的值返回
new
和delete
的原理1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// new circle(...)
{
void *temp=operator new(sizeof(circle)); //分配内存
try{
circle *ptr=static_cast<circle*>(temp); //类型转换
ptr->circle(...); //通过指针调用构造函数
return ptr;
}
catch(...){
operator delete(ptr);
throw;
}
}
// delete ptr
if(ptr!=nullptr){
ptr->~shape();
operator delete(ptr);
}