智能指针

当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更优雅的方式是使用智能指针,从而实现指针指向的对象的共享。智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。智能指针都位于头文件memory中,智能指针是非线程安全的。

shared_ptr

shared_ptr使用引用计数来实现,既能共享也能拥有。通常的deletr作是调用delete,你也可以实现自己的deleter操作,比如你有一个用new[]开辟的内存,则需要自己定义deleter来调用delete[]。如:

1
2
3
4
5
6
std::shared_ptr<int> p(new int[10], 
[](int *p){
delete[] p;
});
//也可以使用std::default_delete<int[]>()
std::shared_ptr<int> p(new int[10], std::default_delete<int[]>());

shared_ptr常用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
shared_ptr<T> p(q) //必须直接初始化,不能隐式
shared_ptr<T> p(u)
shared_ptr<T> p(q, d)
shared_ptr<T> p(p, d)
p.reset()
p.reset(q)
p.reset(q, d)
p.unique()
p.use_count()
p.get() //得到原始指针

//工厂函数
make_shared<T>(args)产生一个T类型的智能指针

shared_ptr的应用

1
2
3
4
5
6
7
8
9
10
11
12
/*
应用于工厂模式下,工厂模式一般要返回一个指针,但用户可能忘记delete,因此可以用shared_ptr
*/

class Foo
{

};

shared_ptr<Foo> create_foo()
{
return make_shared<Foo>();
}

注意问题

1
2
3
4
5
6
int* p = new int;
shared_ptr<int> sp1(p);
shared_ptr<int> sp2(p);
/*
上述做法是错误的,这样两个shared_ptr关联到了同一块内存,最终将会产生两次delete操作。最好的办法就是在创建时初始化。
*/

weak_ptr

weak_ptr是shared_ptr辅助类,主要解决一下两个问题:
1.循环引用,如果两个对象用shared_ptr循环引用,那么use_count将永远是1,无法清除内存;
2.当你想要共享一个对象,但不想拥有的时候,仅仅只是为了看看这个对象存不存在。
weak_ptr并不增加引用计数,当对象最后一个shared_ptr与之失去关联的时候,weak_ptr自动变为空。

1
2
3
wp.expired() //若无任何shared_ptr引用,则返回true
wp.lock() //产生一个相应的shared_ptr
wp.use_count //返回相应引用计数

unique_ptr

unique_ptr独占对象,这是与shared_ptr不同之处,没有共享这个特性,因此其没有拷贝赋值等相关操作,另外一个与其不同地方在于对于数组的创建,和shared_ptr不同,unique_ptr不需要自己定义删除器。在传递T的位置换成T[]就行。下面是其部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace std
{
template <typename T, typename D = default_delete<T>>
class unique_ptr
{
public:
T& operator*() const;
T& operator->() const;
};

template <typename T, typename D>
class unique_ptr<T[], D>
{
public:
T& operator[](size_t i) const;
};
}
/*
可以看出处理数组是一个部分特例化的类,并且该类重载了[]操作符
*/