c++中的智能指针

来源:互联网 发布:mac应用商店 英文 编辑:程序博客网 时间:2024/06/05 17:52

一、为什么需要智能指针

智能指针是为了解决动态内存的使用很容易出错的问题。c++原始的动态内存管理是通过new和delete这一对运算符来完成的,但是它们的使用经常容易出错。总的来说,它们有以下三个常见的问题:

1、忘记delete内存

这样常常导致人们所说的“内存泄漏”问题,因为这种内存永远不可能归还和释放,而且这种问题只有等程序运行很长时间,等内存耗尽之后才能检测到。看下面的一个例子:

Foo *factory(T arg){    return new Foo(arg);}void use_factory(T arg){    Foo *p = factory(arg);    // 使用p,但是不delete它    // p离开了它的作用域,但是它指向的内存没有释放;}

factory函数在堆上申请Foo大小的空间,use_factory使用这块空间,但是离开了use_factory函数体之前,并没有释放这块空间,因为p是唯一指向这块空间的指针,一旦use_factory函数返回,没人会知道这块空间到底是什么,这样导致这块空间的地址丢失,使这块空间永远无法释放。

2、使用已经释放掉的对象

当我们delete一个指针之后,指针值变为无效了,但是这个指针任然保留着之前的地址。为了防止我们再使用这个无效的地址,一般有两种做法:一种是利用作用域,在这个作用域之内释放掉内存,离开了作用域就无法再访问这个指针;另一种是将这个指针设置为nullprt。但是第二种做法还是具有潜在的问题:

int *p(new int(42));auto q = p;delete p;p = nullptr;

这样在delete p之后也将p设置为nullptr,但是这样就万事大吉了吗?不是的,我们还可以通过q访问这个无效的地址。。。

3、对同一块内存释放两次

当有两个指针指向同一个动态分配的对象时,就会出现这样的问题。

二、智能指针的用法

智能指针有四种:auto_ptr, shared_ptr, unique_ptr, weak_ptr。C++11中支持后三种。
shared_ptr与unique_ptr共享的操作
这里写图片描述
shared_ptr独有的操作
这里写图片描述
unique_ptr独有的操作
这里写图片描述
weak_ptr独有的操作
这里写图片描述

简单来说shared_ptr指向某一个对象,可以和多个shared_ptr共同指向同一个对象,他们共同维持一个引用计数,当引用计数为0,说明没有shared_ptr指向这个对象,不需要他了,就自动释放内存。
unique_ptr是“独占一个对象”,当它被销毁,它所指的对象也被销毁。
weak_ptr是相对于shared_ptr而言的,如果说shared_ptr是“铁丝”绑在对象上,那么weak_ptr就是“棉线”粘在对象上的,不会增加shared_ptr的引用计数,最后一个shared_ptr要释放该对象,即使有weak_ptr指向它,也会进行释放,不会考虑weak_ptr的感受。。

三、智能指针就真的安全吗?

智能指针很好用,但是它也不是绝对安全的,我们要知道其中的陷阱。

1、不要混合使用普通指针和智能指针
void process(shared_ptr<int> ptr){    //使用ptr    // ptr离开作用域,被销毁}int *x(new int(1024));process(x);//错误,不能将int*转化成shared_ptrprocess(shared ptr<int>(x));//可以,但是会释放内存int j = x; // 未定义,x是一个空悬指针

在这里,process(shared ptr (x))将普通指针显示构造了一个临时的shared_ptr,此时它的引用计数为1。离开了这个函数体之后,这个临时的shared_ptr会被销毁,此时引用计数为0,所以也会把x这块区域给销毁。。

2、不要使用get初始化另一个智能指针或为智能指针赋值
shared_ptr <int> p(new int(42));int *q = p.get();{       //新的作用域    //独立创建一个临时的shared_ptr    shared_ptr<int> (q);}int foo = *p;// 未定义:p指向的内存已经被销毁了

在这里,p,q指向相同的内存区域,但是因为他们是独立创建的,因此各自的引用计数为1。离开作用域之后会被销毁。导致p指向的内存区域无效。

一些tips:
1. 不适用相同的内置指针值初始化多个职能指针
2. 不delete get()返回的指针;
3. 不使用get() 初始化或reset()另一个智能指针;
4. 如果使用了get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了;
5. 如果你使用的智能指针管理的资源不是new分配的内存,记住传递给它一个删除器。

原创粉丝点击