12
-
智能指针 下面三个定义在 memory 头文件中
- shared_ptr 允许多个指针指向一个对象
- unique_ptr 独占指针所指向的对象
- weak_ptr 指向share_ptr所管理的对象
-
默认初始化的智能指针为空指针nullptr
-
make_shared\<T\>(args)
返回一个share_ptr 不传递任何参数时进行值初始化
-
一般使用动态生存期的资源的类有以下几种原因
- 程序不知道自己需要使用多少对象
- 程序不知道所需对象的准确类型
- 程序需要在对各对象间共享数据
share_ptr
-
share_ptr会自动销毁其管理的对向
-
share_ptr还会自动释放相关联的内存
当动态对向不在被使用时 share_ptr会自动释放动态对象
如果是new的对象不再需要的话一定要手动delete 但是share_ptr就可以自动销毁释放
关于这一点必须注意的是 share_ptr 只有在引用计数为 0 时才会销毁
举个例子 假设智能指针在一个map中 不需要的话一定要erase掉 不然其指向的内存是不会释放的
new和delete直接管理内存
-
new出来的是默认初始化的 比如
auto p = new int;
这里的p就默认初始化 所以其值未定义 -
new失败会抛出一个bad_alloc异常
-
delete p;执行两个动作 销毁指针指向的对象 释放内存
-
传递给delete的必须是new分配的内存或者是空指针nullptr 将相同的指针多次delete也是未定义行为
-
delete之后记得重置为nullptr可以稍微避免多次delete 但是这只能提供有限的保护 并不能确定没有其他指针还指向这块被释放的内存
如下这个p被delete之后释放了其指向的内存 其实q此时也无效了 但是却无法检测 这就是直接new和delete最大的弊端int *p(new int(42)); auto q = p; delete p; p = nullptr;
share_ptr和new结合使用
-
可以使用new返回的指针去初始化智能指针 接受指针参数的构造函数是explicit的只能使用直接初始化
-
当一个share_ptr绑定到一个new的普通指针时 那个就不应该在使用这个内置指针 因为你不知道什么时候对象会被智能指针销毁
-
智能指针定义了一个
get
方法 返回一个内置指针- 使用get返回指针的代码不能delete此指针 delete了那就gg
- 将另一个智能指针绑定到这个get返回的指针也是错误的 因为这样会使两个独立的智能指针指向一个内存
这样一个智能指针失效释放了 会导致另一个智能指针的行为未定义 gg
-
智能指针陷阱
- 不要用相同的内置指针值初始化或者reset多个智能指针
- 同上不能用 get() 返回的指针初始化或者reset另一个智能指针
- 不能delete get() 返回的指针
- 使用了 get() 返回指针的话 需要记住在share_ptr释放之后这个 get() 的指针会无效
- 智能指针管理的不是new的资源记住需要传递一个delete参数
unique_ptr 和 weak_ptr
-
特别要记住release成员函数不会释放内存
-
unique_ptr独占对象 所以不允许拷贝 但是有一个例外情况 可以拷贝或者赋值一个将要被销毁的对象 参考后面的
最常见的例子就是可以从函数返回一个unique_ptr对象 -
weak_ptr是一个不管理对象生存周期的指针 指向一个shared_ptr管理的对象
将weak_ptr绑定到shared_ptr不会增加shared_ptr的引用计数 -
weak_ptr的对象可能不存在 简单使用如下
if (shared_ptr<int> np = wp.lock()){}
-
这里有一个使用智能指针定义begin和end的例子
动态数组
-
new int[0] 个数为0也是允许的 但是这返回的指针类似尾指针的效果 无法解引用 可以像使用尾指针一样始终这个返回的指针
-
delete [] pa; 会
逆序
销毁元素 -
指向数组的unique_ptr
unique_ptr<int[]> u;
u.release()会执行delete []释放数组 这与普通unique_ptr不一样 普通的unique_ptr的release不会释放内存 -
指向数组的unique_ptr支持下标运算
-
shared_ptr不直接数组 管理动态数组的话需要自定义删除器 并且不支持下标运算符 绑定数组的话需要使用get()+n进行访问
使用lambda传递delete参数shared_ptr<int> sp(new int[10], [](int *p){delete []p;})
allocator类
-
new将分配内存和对象的构造结合在了一起 delete将对象的析构和内存的释放组合在了一起
没有默认构造函数的类也无法动态分配数组 -
allocator定义在memory中 帮助我们将内存分配和对象构造分开
使用未构造的内存其行为未定义
-
具体方法
P428