- 生存期
- 全局对象:程序启动时分配,程序结束时销毁
- 局部对象:进入其定义所在的程序块时被创建,离开块时被销毁
- static对象:第一次使用前被分配,程序结束时销毁
- 动态分配的对象:只有当显式地被释放时,才会被销毁
- 程序内存:
- 静态内存:局部static对象,类static数据成员,定义在任何函数外的变量→使用前分配内存,程序结束时销毁;
- 局部static对象:令局部变量的声明周期贯穿函数调用及之后的时间,在程序执行路径第一次经过对象定义语句时初始化,知道程序终止被销毁
- 栈内存:定义在函数内的非static对象→仅在其定义的程序块运行时存在;
- 分配在静态或者栈内存中的对象由编译器自动创建和销毁
- 动态内存:动态分配,生存期由程序控制→显示创建,显示销毁。
- 静态内存:局部static对象,类static数据成员,定义在任何函数外的变量→使用前分配内存,程序结束时销毁;
- 动态内存:
- new创建,delete销毁→确保正确释放内存困难。
- (c++11)智能指针:shared_ptr 允许多个指针指向同一对象,unique_ptr 不允许...., weak_ptr 伴随类?,弱引用?,指向shared_ptr指向的对象。→memory头文件中
- 使用动态生存期的资源:
- 程序不知道自己需要多少对象;
- 程序不知道所需对象的准确类型;
- 程序需要在多个对象间共享数据。
零、术语表
一、动态内存和智能指针
- shared_ptr类
模板类→创建:shared_ptr<string> p1; shared_ptr<list<int>> p2;
-
初始化:
- 默认初始化→保存空指针;
- 其他方式?(12.1.3)
操作:
shared_ptr和unique_ptr共有:shared_ptr<T> sp;p;*p;p->mem;p.get()?; swap(p,q);p.swap(q)
shared_ptr 独有:make_shared<T> (args);shared_ptr<T> p(q);p=q;p.unique();p.use _count()-
make_shared函数
- 最安全的分配和使用动态内存的方法,memory头文件;
- 类似顺序容器的emplace成员,用其参数来构造给定类型的对象;
eg. shared_ptr<int> p1 = make_shared<int>(42);
shared_ptr<string> p2 = make_shared<string>(10,'9'); - 不传递参数时→值初始化;
-
shared_ptr的工作原理:
- 可认为每个shared_ptr都有一个关联的计数器(引用计数);
- 一旦计数器变为0,会自动释放所管理的对象→通过析构函数销毁, - shared_ptr的析构函数 递减它指向对象的引用计数/计数为0时释放内存;
- 计数器:
- 拷贝→计数器递增;
- 赋值p = q → p指向对象计数递减,q指向对象计数递增;
- 返回p→ 需要向调用者传递一个p的拷贝,计数递增。
- shared_ptr被销毁,例如一个局部的shared_ptr离开其作用域→计数器递减
- 由于在最后一个shared_ptr销毁前内存都不会释放,所以需要保证shared_ptr在无用之后不再保留;
回顾知识点:
基于const的重载→通过区分成员函数是否是const对其重载,分别适用于常量版本和非常量版本的对象。
initializer_list→6.2.6
- 直接管理内存
- 使用new分配和初始化对象:new无法为分配的对象命名,而是返回一个指向该对象的指针:int *pi = new int;
- 初始化:
- 默认初始化→默认状况下使用,(内置类型或组合类型对象的值未定义,类类型用默认构造函数);
- 定义变量时没有指定初值,则变量被默认初始化;
- 内置类型,定义于任何函数体之外被初始化为0,否则不被初始化,值是未定义的→建议初始化每一个内置类型的变量
- 直接初始化→圆括号,int *pi = new int(1024), string *s = new string(10,'9');
- 列表初始化 vector<int> *p = new vector<int>{0,1,2,3,4,5}
- 值初始化:→int *p = new int();
- 内置类型,初始值设为0
- 其余类型,默认初始化
- 默认初始化→默认状况下使用,(内置类型或组合类型对象的值未定义,类类型用默认构造函数);
- 可以用new分配const对象:const int *pci = new const int(1024)→该对象必须初始化。
- 使用delete释放内存:接受一个指向想要释放对象的指针:delete p,p必须指向一个动态分配的对象或空指针!,动态分配的const对象不可被改变但可被销毁。
- 执行两个动作:销毁给定指针指向的对象,释放对应的内存。
- 指向动态对象的指针必需记得在不用时释放内存,eg,当一个指针离开其作用域,它指向的对象什么都不会发生,如果是一个指向动态对象的指针,那么内存将不被释放。
-
new,delete使用常见问题:
- 忘记delete内存;
- 使用已经释放掉的对象;
- 同一块内存释放两次;
- 空悬指针:指向一块曾经保存数据对象,但现在已经无效的内存的指针,如:int *p = new int(43); auto q = p; delete p;→q现在是一个空悬指针。
shared_ptr和new结合使用
unique_ptr
weak_ptr