智能指针

智能指针其实挺容易的。

 

 

1. scoped_ptr<T>

将指针自身的生命周期与对象绑定,“我死之日也是你亡之时”

 例如:

#include "boost/smart_ptr.h"

void Sample1_ScopedPtr()

  boost::scoped_ptr<CSample>

       samplePtr(new CSample);

  if (!samplePtr->Query() )

  // just some function...

    return;   

  samplePtr->Use();
 
当我们使用例外的时候处理指针是特别烦人的事情(容易忘记销毁它)。使用scoped_ptr 指针就能够在函数结束的时候自动销毁它,因为这时scope_ptr也要完蛋了。

 2、 shared_ptr

通过引用计数来管理对象的生命,引用计数听过好多遍了--对引用次数作个记录,但要关键要搞清楚的是这个“计数”是放在哪儿的?计数是在直接由对象原始指针创建shared_ptr时在堆上分配的;而通过拷贝构造或赋值得到的shared_ptr的计数则指向此计数了。这注定了两件事:

1.不能有多个shared_ptr直接由原始指针创建而来 2.不能形成循环计数。

再有一个重点是,从其语义上,要对对象的生命周期做出管理。如果语境中,不需要一个指针具有管理对象生命周期的语义,此时再使用shared_ptr有可能会违背以上两点。此时可考虑使用week_ptr

 

void Sample2_Shared(){

  // (A) 创建Csample类的一个实例和一个引用。

  boost::shared_ptr<CSample> mySample(new CSample);

  printf("The Sample now has %i references\n", mySample.use_count()); // The Sample now has 1 references

  // (B) 付第二个指针给它。

  boost::shared_ptr<CSample> mySample2 = mySample; // 现在是两个引用指针。

  printf("The Sample now has %i references\n", mySample.use_count());

  // (C) 设置第一个指针为空。

  mySample.reset();

  printf("The Sample now has %i references\n", mySample2.use_count());  // 一个引用

  // 当mySample2离开作用域的时候,对象只有一个引用的时候自动被删除。

一个误用的例子:

class foo {
public:
    typedef std::shared_ptr<foo> type_ptr;
    //blablabla....
 
    type_ptr what_are_you_want_to_do() {
        // 一堆不知道干嘛的代码后
        return type_ptr(this);
    }
};
 
int main() {
    foo::type_ptr p = foo::type_ptr(new foo());
    p->what_are_you_want_to_do();
    return 0;
}

此处 return type_ptr(this) 语义不需要对foo对象的生命周期管理,使用shared_ptr是不合理的。

但也确实脑慢了就容易错啊。

 

3、 使用weak_ptr跳出循环

 

weak_ptr并不对对象的生命周期进行参与,它的座右铭是“我只看看,不说话”,对象活着就用,不存在就返回空指针。

其原理是,不对引用计数作修改。

 

 4、 Intrusive_ptr——轻量级共享智能指针

shared_ptr比普通指针提供了更完善的功能。有一个小小的代价,那就是一个共享指针比普通指针占用更多的空间,每一个对象都有一个共享指针,这个指针有引用计数器以便于释放。但对于大多数实际情况,这些都是可以忽略不计的。

前面三个指针对对象没啥要求,但intrusive_ptr 则要对象本身已经有了一个对象引用计数器,也是“侵入”的来源。此时因为“计数”在对象内,下面这样就没啥问题了(与shared_ptr相比):

p = new P()
f = boost::intrusive_ptr<P>(p)
g = boost::intrusive_ptr<P>(p)
 

如果你要使用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

posted @ 2012-03-22 12:21  justin_s  阅读(2390)  评论(0编辑  收藏  举报