C++中,动态内存的管理是通过:new
在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete
接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。
动态内存很容易出问题,因为确保在正确的时机释放内存很困难。有时会忘了释放内存,产生内存泄露;有时还有指针引用内存就释放了它,会产生UAF。
为了更容易更安全地使用动态内存,新的标准库提供了两种智能指针(smart pointer)
类型来管理动态对象。这两种智能指针的区别在于管理底层指针的方式:shared_ptr
允许多个指针指向同一个对象;unique_ptr
则独占所指向的对象。标准库还定义了一个名为weak_ptr
的伴随类,它是一种弱引用,指向shared_ptr
所管理的对象。
shared_ptr类
类似vector,智能指针也是模板。创建一个智能指针时,必须提供额外信息(指针指向的类型)
1 | shared_ptr<string> p1; // shared_ptr,可以指向string |
shared_ptr和unique_ptr都支持的操作
操作 | 作用 |
---|---|
p | 将p用作一个条件判断,若p指向一个对象,则为true |
*p | 解引用p,获得它指向的对象 |
p->mem | 等价于(*p).mem |
p.get() | 返回p中保存的指针 |
swap(p, q) | 交换p和q中的指针 |
shared_ptr独有的操作
make_shared
函数,在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。
1 | // main.cpp |
每个shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)
。
拷贝一个shared_ptr时,计数器都会递增。如:当用一个shared_ptr初始化另一个shared_ptr,或将它作为参数传递给一个函数以及作为函数的返回值时,它所关联的计数器就会递增。
当给shared_ptr赋予一个新值或是shared_ptr被销毁时,计数器就会递减。
一旦一个shared_ptr的计数器变为0,他就会自动释放自己所管理的对象。
unique_ptr类
与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象。当unique_ptr被销毁时,它所指向的对象也被销毁。与shared_ptr不同,没有类似make_shared的标准库函数返回一个unique_ptr。定义一个unique_ptr时,需要将其绑定到一个new返回的指针上:
1 | unique_ptr<double> doup(new double(3.14)); |
由于unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作。但可以通过调用release
或reset
将指针的所有权从一个(非const)unique_ptr转移给另一个unique:
1 | // 将所有权从strp转移给strp2 |
release
成员返回unique_ptr当前保存的指针,并将其置空。因此strp2被初始化为strp1原来的指针,strp1被置空。reset
成员接受一个可选的指针参数,令unique_ptr重新指向给定的指针,原来指向的对象被释放。
weak_ptr
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。最后一个shared_ptr被销毁,对象就会被销毁,即使还有weak_ptr指向这个对象。
1 | auto p = make_shared<int>(42); |