smart pointer 智能指针
智能指针和普通指针的区别在于智能指针实际上是对普通指针加了一层封装机制,这样的一层封装机制的目的是为了使得智能指针可以方便的管理一个对象的生命期。
在C++中,我们知道,如果使用普通指针来创建一个指向某个对象的指针,那么在使用完这个对象之后我们需要自己删除它,例如:
ObjectType* temp_ptr = new ObjectType();
temp_ptr->foo();
delete temp_ptr;
很多材料上都会指出说如果程序员忘记在调用完temp_ptr之后删除temp_ptr,那么会造成一个悬挂指针(dangling pointer),也就是说这个指针现在指向的内存区域其内容程序员无法把握和控制,也可能非常容易造成内存泄漏。
可是事实上,不止是“忘记”,在上述的这一段程序中,如果foo()在运行时抛出异常,那么temp_ptr所指向的对象仍然不会被安全删除。
在这个时候,智能指针的出现实际上就是为了可以方便的控制对象的生命期,在智能指针中,一个对象什么时候和在什么条件下要被析构或者是删除是受智能指针本身决定的,用户并不需要管理。
根据具体的条件,我们一般会讨论这样几种智能指针,而如下所说的这些智能指针也都是在boost library里面定义的 (http://www.boost.org/doc/libs/1_50_0/libs/smart_ptr/smart_ptr.htm):
1) scoped_ptr(unique_ptr):
这是比较简单的一种智能指针,正如其名字所述,scoped_ptr所指向的对象在作用域之外会自动得到析构,一个例子是:http://www.boost.org/doc/libs/1_50_0/libs/smart_ptr/scoped_ptr.htm
此外,scoped_ptr是non-copyable的,也就是说你不能去尝试复制一个scoped_ptr的内容到另外一个scoped_ptr中,这也是为了防止错误的多次析构同一个指针所指向的对象。
2) shared_ptr:
很多人理解的智能指针其实是shared_ptr这个范畴。
shared_ptr中所实现的本质是引用计数(reference counting),也就是说shared_ptr是支持复制的,复制一个shared_ptr的本质是对这个智能指针的引用次数加1,而当这个智能指针的引用次数降低到0的时候,该对象自动被析构。
需要特别指出的是,如果shared_ptr所表征的引用关系中出现一个环,那么环上所述对象的引用次数都肯定不可能减为0那么也就不会被删除,为了解决这个问题引入了weak_ptr。
3) weak_ptr:
对weak_ptr起的作用,很多人有自己不同的理解,我理解的weak_ptr和shared_ptr的最大区别在于weak_ptr在指向一个对象的时候不会增加其引用计数,因此你可以用weak_ptr去指向一个对象并且在weak_ptr仍然指向这个对象的时候析构它,此时你再访问weak_ptr的时候,weak_ptr其实返回的会是一个空的shared_ptr。
实际上,通常shared_ptr内部实现的时候维护的就不是一个引用计数,而是两个引用计数,一个表示strong reference,也就是用shared_ptr进行复制的时候进行的计数,一个是weak reference,也就是用weak_ptr进行复制的时候的计数。weak_ptr本身并不会增加strong reference的值,而strong reference降低到0,对象被自动析构。
为什么要采取weak_ptr来解决刚才所述的环状引用的问题呢?需要注意的是环状引用的本质矛盾是不能通过任何程序设计语言的方式来打破的,为了解决环状引用,第一步首先得打破环,也就是得告诉C++,这个环上哪一个引用是最弱的,是可以被打破的,因此在一个环上只要把原来的某一个shared_ptr改成weak_ptr,实质上这个环就可以被打破了,原有的环状引用带来的无法析构的问题也就随之得到了解决。
参考链接:
链接:https://www.zhihu.com/question/20368881/answer/14918675 来源:知乎