这篇文章主要介绍 boost中的智能指针的使用。

    内存管理是一个比较繁琐的问题,C++中有两个实现方案: 垃圾回收机制和智能指针。垃圾回收机制因为性能等原因不被C++的大佬们推崇,
而智能指针被认为是解决C++内存问题的最优方案。

1. 定义

     一个智能指针就是一个C++的对象, 这对象的行为像一个指针,但是它却可以在其不需要的时候自动删除。注意这个“其不需要的时候”,
这可不是一个精确的定义。这个不需要的时候可以指好多方面:局部变量退出函数作用域、类的对象被析构……。所以boost定义了多个不同的智能指针来管理不同的场景。

shared_ptr<T> 内部维护一个引用计数器来判断此指针是不是需要被释放。是boost中最常用的智能指针了。
scoped_ptr<t> 当这个指针的作用域消失之后自动释放
intrusive_ptr<T> 也维护一个引用计数器,比shared_ptr有更好的性能。但是要求T自己提供这个计数器。
weak_ptr<T> 弱指针,要和shared_ptr 结合使用
shared_array<T> 和shared_ptr相似,但是访问的是数组
scoped_array<T> 和scoped_ptr相似,但是访问的是数组
2. Boost::scoped_ptr<T>

    scoped_ptr 是boost中最简单的智能指针。scoped_ptr的目的也是很简单,
当一个指针离开其作用域时候,释放相关资源。特别注意的一定就是scoped_ptr
不能共享指针的所有权也不能转移所有权。也就是说这个内存地址就只能给的声明的变量用,不能给其他使用。

    下面是scoped_ptr的几个特点:

* scoped_ptr的效率和空间的消耗内置的指针差不多。
* scoped_ptr不能用在标准库的容器上。(用shared_ptr代替)
* scoped_ptr 不能指向一块能够动态增长的内存区域(用scoped_array代替)

<> 1 class test
2 {
3 public:
4 void print()
5 {
6 cout << "test print now" <<endl;
7 }
8 };
9 int _tmain(int argc, _TCHAR* argv[])
10 {
11 boost::scoped_ptr<test> x(new test);
12 x->print();
13 return 0;
14 } <>

3.Boost::shared_ptr<T>

    shared_ptr 具有如下几个特点:

* 在内部维护一个引用计数器, 当有一个指针指向这块内存区域是引用计数+1, 反之-1, 如果没有任何指针指向这块区域, 引用计数器为0,释放内存区域。
* 可以共享和转移所有权。
* 可以被标准库的容器所使用
* 不能指向一块动态增长的内存(用share_array代替)
我们可以看下如下例子:

<> 1 int _tmain(int argc, _TCHAR* argv[])
2 {
3 boost::shared_ptr<test> ptr_1(new test);
4 ptr_1->print();//引用计数为1
5 boost::shared_ptr<test> ptr_2 = ptr_1;
6 ptr_2->print();//引用计数为2
7 ptr_1->print();// 引用计数还是为2
8 return 0;
9 } <>

4. Boost::intrusive_ptr<T>

    intrusive_ptr 的主要和share_ptr一样, 对比share_ptr,其效率更高,但是需要自己维护一个引用计数器。


shared_ptr比普通指针提供了更完善的功能。有一个小小的代价,那就是一个共享指针比普通指针占用更多的空间,每一个对象都有一个共享指针,这个指针有引用计数器以便于释放。但对于大多数实际情况,这些都是可以忽略不计的。intrusive_ptr
提供了一个折中的解决方案。它提供了一个轻量级的引用计数器,但必须对象本身已经有了一个对象引用计数器。这并不是坏的想法,当你自己的设计的类中实现智能指针相同的工作,那么一定已经定义了一个引用计数器,这样只需要更少的内存,而且可以提高执行性能。如果你要使用intrusive_ptr
指向类型T,那么你就需要定义两个函数:intrusive_ptr_add_ref
和intrusive_ptr_release。下面是一个简单的例子解释如何在自己的类中实现:

#include "boost/intrusive_ptr.hpp" // forward declarations class CRefCounted;
namespace boost { void intrusive_ptr_add_ref(CRefCounted * p); void
intrusive_ptr_release(CRefCounted * p); }; // My Class class CRefCounted {
private: long references; friend void
::boost::intrusive_ptr_add_ref(CRefCounted * p); friend void
::boost::intrusive_ptr_release(CRefCounted * p); public: CRefCounted() :
references(0) {} // initialize references to 0 }; // class specific
addref/release implementation // the two function overloads must be in the
boost namespace on most compilers: namespace boost { inline void
intrusive_ptr_add_ref(CRefCounted * p) { // increment reference count of object
*p ++(p->references); } inline void intrusive_ptr_release(CRefCounted * p) { //
decrement reference count, and delete object when reference count reaches 0 if
(--(p->references) == 0) delete p; } } // namespace boost

 这是一个最简单的(非线程安全)实现操作。但作为一种通用的操作,如果提供一种基类来完成这种操作或许很有使用价值,也许在其他地方会介绍到。        

5. Boost::weak_ptr<T>

    

强引用和弱引用的比较:


一个强引用当被引用的对象活着的话,这个引用也存在(就是说,当至少有一个强引用,那么这个对象就不能被释放)。boost::share_ptr就是强引用。相对而言,弱引用当引用的对象活着的时候不一定存在。仅仅是当它存在的时候的一个引用。

boost::weak_ptr<T>
是执行弱引用的智能指针。当你需要它的时候就可以使用一个强(共享)指针指向它(当对象被释放的时候,它为空),当然这个强指针在使用完毕应该立即释放掉,在上面的例子中我们能够修改它为弱指针。

struct CBetterChild : public CSample { weak_ptr<CDad> myDad; void BringBeer()
{ shared_ptr<CDad> strongDad = myDad.lock(); // request a strong pointer if
(strongDad) // is the object still alive? strongDad->SetBeer(); // strongDad is
released when it goes out of scope. // the object retains the weak pointer } };
    weak_ptr 就是一个弱指针。weak_ptr 被shared_ptr控制,
它可以通过share_ptr的构造函数或者lock成员函数转化为share_ptr。

    weak_ptr的一个最大特点就是它共享一个share_ptr的内存,但是无论是构造还是析构一个weak_ptr 都不会影响引用计数器。

<> 1 int _tmain(int argc, _TCHAR* argv[])
2 {
3 boost::shared_ptr<test> sharePtr(new test);;
4 boost::weak_ptr<test> weakPtr(sharePtr);
5 //weakPtr 就是用來保存指向這塊內存區域的指針的
6 //干了一大堆其他事情
7 boost::shared_ptr<test> sharePtr_2 = weakPtr.lock();
8 if (sharePtr_2)
9 sharePtr_2->print();
10 return 0;
11 } <>

6. Boost::shared_array<T> 和Boost::scoped_array<T>

    前面提到过shared_ptr和scoped_ptr不能用于数组的内存(new
[]),所以shared_array和scoped_array就是他们的代替品。我们可以看下shared_array的用法

<> 1 int _tmain(int argc, _TCHAR* argv[])
2 {
3 const int size = 10;
4 boost::shared_array<test> a(new test[]);
5 for (int i = 0; i < size; ++i)
6 a[i].print();
7 return 0;
8 } <>

7. 使用智能指针的几个注意点

    下面是几个使用智能指针需要注意的地方:

* 声明一个智能指针的时候要立即给它实例化, 而且一定不能手动释放它。
* …_ptr<T> 不是T* 类型。所以:
                a: 声明的时候要…_ptr<T> 而不是….._ptr<T*>

                b:不能把T* 型的指针赋值给它

                c: 不能写ptr=NULl, 而用ptr.reset()代替。

* 不能循环引用。
* 不要声明临时的share_ptr, 然后把这个指针传递给一个函数
8. 总结

    智能指针使用上还是比较简单的, 而且能比较有效得解决C++内存泄露的问题,各位使用C++的童鞋赶快用起来吧。

技术
©2019-2020 Toolsou All rights reserved,
LinkedHashMap基本用法&使用实现简单缓存 dedecms网站被黑 劫持到其他网站如何解决苹果不送充填器耳机真为环保?可能还是为了赚钱吧图片格式转换错误总结-myBatis plus 分页numpy:多维数组的创建用C语言做很简单的飞机游戏Keras保存与加载模型(JSON+HDF5)福布斯中国汽车富豪榜:何小鹏第11 李想第14 李斌第15hive大量小文件处理方法总结