介绍的shard_ptr
和unique_ptr
都在头文件<memory>
中哦
shard_ptr
是一个模板, 因此使用的时候需要提供类型. 作为智能指针, shard_ptr可以记录指向的内存有多少使用者. 这一点跟在OS中学的进程很像. 当计数器为0的时候, 指向的内存被自动delete掉.
shared_ptr有几种方法.
.get()
方法会返回一个普通类型的指针, 可以用于不支持智能指针的区域, 但是注意, 这个指针千万不能被delete掉!,或者将.get()
得到的指针初始化另一个智能指针 (因为两个智能指针的计数器不共享).
.unique()
将检查这个指针是否是独享的moment注意这个方法在C++20中被废弃了
.use_count()
检查共享总数目.
.reset(arg)
如果提供了arg, 就让这个指针指向arg; 如果不提供, 则释放所有权. 简而言之, 重置了这个智能指针
对于要返回智能指针的函数, 生成匿名shared_ptr的方法是使用语句``make_shared<TYPE> (args).
智能指针的初始化是explicit的, 因此我们不能让编译器隐式转换, 初始化参数必须和模板高度一致. 智能指针初始化的时候还可以提供额外一个参数d, d是一个指向函数的指针, 这个函数将代替默认的delete函数
new
可以使用auto
来声明一个变量来接受new的指针, 但是初始化参数只能有一个(让编译器用来判断auto的到底是一个什么类型). 顺便一提的是, 如果内存分配失败, new会抛出一个bad_alloc的异常, 但是如果我们包含了头文件<new>
的话, 可以在new后面提供参数(nothrow)
, 让new返回空指针, 使用方式类似下面:
auto p1 = new(nothrow) int(8);
//p1 是int*类型
delete一个指针的时候, 只是将内存区域释放, 但是这个指针还在指向它(我们俗称这种指针为野指针), 好的习惯是每次delete之后都将这个指针指向nullptr. 另外一个手动管理的缺陷是: 如果出现了异常退出或者函数异常结束, 你的delete代码可能不会被执行, 但是智能指针可以保证没哟使用者的时候一定会被智能释放. 可见手动new及其繁琐, 超级推荐大家直接使用智能指针
自动管理和手动管理时, 可能会有混乱:
int *p = new int(8);
shared_ptr<int> y(p);//此时p已经被自动管理了,随时会被自动释放, 因此p不一定是一个时刻有效的指针
unique_ptr
首先先讲一下他和shared_ptr最大的不同: 如果自定义析构函数, 则在模板类型必须说明析构函数的类型(通常我们直接用decltype*):unique_ptr<int, decltype(mydes )*> p(&c, mydes);
unique_ptr有一个方法.release()
方法, 会放弃对于指针的所有权, 并返回这个指针. 可以用于指针的传递, 如:p1.reset( p2.release())
, 这条语句将p2的指针交给了p1. 注意:如果release()之后没有接收者,这片内存会永远存在, 因为没有人指向
weak_ptr
简述: 可以指向一个shared_ptr, 但是不影响shared_ptr的指针count计数器.
含有的方法如下
-
.expired()
,检查指向的内容是否已被清空? 一般weak_ptr调用前都要检查一下, 防止指向的shared_ptr早就清空了 -
lock()
, 返回一个shared_ptr, 如果原来的shared_ptr已经被清空, 则返回空指针 -
use_count()
, 检查shared_ptr有多少个使用者
动态数组
产生的原因: 想在使用的时候才指定数组的大小. 方法:int *p = new int[ n ] (arg..)
. 对应的delete方法也变成了delete[ ]
只有unique_ptr有动态数组的管理能力, 可以unique_ptr<int[ ]>p(new int[ 5 ])
,因为shared_ptr使用的是delete
析构而不是delete[ ]
. 因此我们如果想使用shared_ptr管理动态数组, 需要手动指定析构函数(这里我们使用lambda表达式) shared_ptr <int> p(new int[ 10 ], [](int *p){delete[ ] *p})
. 同样地, shared_ptr不支持下标访问, 因此只能使用.get()+i
的基地址偏移法访问元素.
allocator
产生的原因: 对于某些new出来的指针, 我们不想初始化, 只是想在使用的时候初始化,而现在只是开辟了地址.(节约时间)
方法:
- 开辟一个分配器模板
allocator<int> alloc
-
auto p = alloc.allocate(n)
开辟n个int大小的生内存,使用指针p指向它 -
.construct(p, arg)
, 在p地址处开始构造, 使用arg作为构造参数. -
.destroy(p)
, 析构p地址 -
.deallocate(p,n)
,从p地址开始的n个int大小都被还给系统, 注意p,n必须和allocate的时候一样大!
相关的方法有两个:
uninitialized_copy(可选_n) (b,e, b2)
, 使用迭代器从b到e来初始化原始内存b2(或者e个b)
uninitialized_fill(可选_n) (raw_b, raw_e, t)
, 将迭代器所指的b到e的原始内存填入t的拷贝
网友评论