智能指针:shared_ptr类
shared_ptr
是一个模板类,智能指针本质是个对象,有一些方法可以调用。
shared_ptr<int> p;
p.get();//获得指针的值(内存地址)
p.use_count();//有几个智能指针指向这个内存地址
p.unique();//如果p.use_count()==1,他返回true
这个类也定义了解引用运算符(*
)和箭头运算符(->
),目的是像使用指针一样使用智能指针。
*p;
p->func();//等价(*p).func();
make_shared() 函数
智能指针有三种初始化方式
shared_ptr<int> p(new int);//用new返回的指针来初始化,但这个构造函数是explicit的,因此,普通指针无法隐式转换成智能指针。
shared_ptr<int> q(p);//用另一个智能指针初始化
shared_ptr<int> p(make_shared<int>(10)); //使用make_shared();他也是一个模板,需要指定类型,后边的括号相当于调用构造函数
//也可以用auto
auto p = make_shared<int>(10);
动态内存会随着智能指针的生命周期而自动释放,当没有一个智能指针指向某块内存,他就会自动释放。也就是p.use_count() == 0
,当然这个代码不可能运行成功,只是方便理解。
注意事项:
-
不要混用智能指针和普通指针,你很难注意智能指针什么时候会自动释放,这时再用普通指针访问会发生错误。
-
不要用智能指针的get()函数来初始化另一个智能指针,这种方法不会增加use_count,因此会double free。
int main() { shared_ptr<C> p(make_shared<C>()); shared_ptr<C> q(p.get()); cout << p.use_count();//输出1 getchar(); return 0; //程序结束p和q都会释放内存,double free }
使用自己的释放操作
引用C++ primer里的例子,假如shared_ptr
指向的是一个网络连接,那么我们希望当这个连接不再使用的时候能够自动释放,这就需要自己定义释放函数。
void end_connection(connection *p)
{
//释放连接
}
void f(destination &d)
{
connection c = connect(d);
shared_ptr<connection> p(&c, end_connection);
//使用连接
//从f退出时,connection会自动调用end_connection关闭
}
unique_ptr
shared_ptr
智能指针可以不同的几个智能指针指向同一块内存,而unique_ptr
只允许一个智能指针(不管是shared_ptr还是unique_ptr)指向这块内存。要想将这块内存变成普通的智能指针,使用p.release()
。
unique_ptr<T> up(new T);
shared_ptr<T> sp(up.release());
up.reset(new int);//重新绑定一个内存地址
unique_ptr使用自己的释放操作
unique_ptr<T, D> p(new T, d);
//D是可调用对象的类型,d是D类型的一个对象
//下边是个例子
void end_connection(connection *p)
{
//释放连接
}
void f(destination &d)
{
connection c = connect(d);
unique_ptr<connection, decltype(end_connection)*> p(&c, end_connection);
//使用连接
//从f退出时,connection会自动调用end_connection关闭
}