内存类型
栈内存
定义在函数内的非static对象
堆内存
在程序运行时分配的对象
静态内存
局部static对象、类static数据成员、定义在任何函数之外的变量
内存问题
内存泄漏
忘记释放内存
非法内存指针
尚有指针引用的内存被释放
智能指针
shared_prt:允许多个指针指向同一对象
unique_prt:“独占”指向对象
weak_prt:指向shared_ptr所管理的对象
都在memory头文件中
shared_ptr类
make_shared函数
在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。
例:shared_ptr p = make_shared(10,‘9’)
weak_ptr
- 是一种不控制所指向对象生命期的指针,指向由也给shared_ptr管理的对象
- 最后一个指向对象的shared_ptr被销毁,对象就会被释放,即使有weak_ptr指针
unique_ptr
- 一个unique_ptr“拥有”它所指向的对象
- 没有类似make_shared的函数返回unique_ptr
- 没有赋值、拷贝操作
拷贝:unique_ptr p1(p2);
赋值:p1 = p3;
3.1可以拷贝或赋值一个将要被销毁的unique_ptr。例如作为参数或返回
3.2 “可以”(编译不出错,但可能出现悬空指针)拷贝一个普通指针或取地址。如下
int *p = new int(2048);
int x;
unique_ptr<int> p1(p); //出现悬空指针
unique_ptr<int> p2(&x); //原始对象非new得来,故unique_ptr执行delete出错
- 通过release或reset移交控制权
unique_ptr<int> p2(p1.release());
unique_ptr<int> p3(new string("abc"));
p2.reset(p3.release());
注:release会切断unique_ptr和它原来管理的对象简的关系。release返回的指针通常用来初始化另一个智能指针或赋值另一个智能指针。
智能指针的计数实现
这个计数器实际上是存储在 shared_ptr
的内部,而不是存储在所指向的对象上。
如果有多个智能指针指向同一个对象,每个智能指针的计数器都会递增。当一个新的智能指针指向了已经被其他智能指针管理的对象时,被管理对象的引用计数会增加。
递增:
①通过一个shared_ptr初始化另一个shared_ptr
②作为参数传递给一个函数
③作为函数返回值
递减:
①给shared_ptr赋新值
②shared_ptr离开作用域
销毁:计数器变为0
动态数组
-
分配一个动态数组,需要在类型名后跟一对方括号。如下:
int *p = new int[get_size()]
-
分配一个数组会得到一个元素类型的指针
-
初始化动态数组。如下
int * p1 = new int[10](); //值初始化
-
动态分配一个大小为0的数组是合法的。
char *cp = new char[0];
-
delete动态分配对象时一定要分清是不是数组
delete p; //p必须指向一个动态分配的对象或空 delete [] p; //p必须指向一个动态分配的数组或空
-
标准库提供管理new分配数组的unique_ptr版本,但shared_ptr没有
unique_ptr<int[]> up(new int[10])
allocator类
string * const p = new string[n]
- 将内存分配与对象构造组合在一起可能会导致不必要的浪费。因为动态内存是默认初始化的。例如本例可能不需要n个string
allocator<string> alloc;
auto const p = alloc.allocate(n);
- 定义一个allocator对象必须指明这个allocator可以分配的对象类型。最终结果是分配n个未初始化的string对象。
auto q = p;
alloc.construct(q++,10,'c');
while(p != q)
alloc.destroy(--q);
- allocator分配的内存是未构造的,需要对内存construct后再访问内容。当对象使用完毕后,需要调用destroy来销毁它们。
alloc.deallocate(p,n);
- 销毁后的内存可以归还给系统