第三部分 资源管理(条款13-17)

来源:互联网 发布:开源中国app源码下载 编辑:程序博客网 时间:2024/05/18 00:34

条款13 以对象管理资源

class Investment{.........};

假设有个工产函数: Investment* createInvestment();

现在:

void f()

{

  Investment* pInv = createInvestment();

  ....

  delete pInv;

}

这个函数看起来是没有什么问题的,但是如果在...部分因为某种原因过早地return了,delete无法执行。那么我们可以把资源放入对象中:

void f()

{

 std::auto_ptr<Investment>pInv(createInvestment());

  .....

}

其中auto_ptr是一个类指针对象(智能指针),析构函数自动对其对象调用delete

由于auto_ptr被销毁后会自动析构,所以不能够让多个auto_ptr 指向同一个对象。如果那样的话,一个对象会删除一次以上。所以auto_ptr有一个性质:通过copy后他会变成null,而复制所得到的指针取得唯一拥有权。

为了解决这个问题它的替代方法是“引用计数型智慧指针”

void f()

{

   ....

   std::tr1::shared_ptr<Investment> pInv(createInvestment());

  ....

}

当然这种行为支持正常的复制了

我们需要注意的是无论是auto_ptr还是shared_ptr都不支持delete[ ],所以不能够分配数组


条款14: 在资源管理类中小心copying行为

   条款13中的观念都表现在heap-based资源上,他们不适合做资源的管理者,我们需要建立自己的资源管理类

 class Lock

{

   public:

   explicit Lock(Mutex* pm):mutexPtr(pm)

   {   lock(mutexPtr);  }

   ~Lock()

    {   unlock(mutexPtr);  }

  private:

    Mutex* mutexPtr;

};

客户用法:

Mutex m;

 ...

{

    Lock m1(&m);//加锁

   ....

} //自动释放锁

现在   Lock m1(&m);

           Lock m2(m1);   //复制会发生什么事情?

大多的做法:

 第一是 禁止复制 class Lock:private Uncopyable{............};

 第二 使用share_ptr 但是不幸的是这个是在指针计数为0时删除,我们要的不是删除是解除锁。针对这种情况shared_ptr提供了一种指定删除器的方法:

class Lock

{

  public :

  explicit Lock(Mutex* pm):mutexPtr(pm,unlock)  //这里使用unlock函数为删除器,当计数为0的时候直接调用这个函数

  {lock(mutexPtr.get()) ;}

private:

  std::tr1::shared_ptr<Mutex> mutexPtr;

};


条款15: 在资源管理类中提供对原始资源的访问

    条款13中  std::tr1::shared_ptr<Investment> pInv(createInvestment());

  现在我们有个函数:

  int daysHeld(const Investment* pi);

 如果直接传入pInv肯定会是错误的,有两种做法可以达到目的

  一个是auto和shared都提供了get函数,所以可以这么做: int days = daysHeld(pInv.get());

  另外利用智能指针对operator-> 和operator*重载

  class Investment

  {

     public: 

    bool isTaxFree() const;

    ....

  };

  Investment* createInvestment();

 std::tr1::shared_ptr<Investment> p1(createInvestment());

  bool taxable1 = !(p1->isTaxFree());

  ....

  std::auto_ptr<Investment> p2 (createInvestment());

 bool taxable2 = !((*p2).isTaxFree()); 

 请记住:

   1.API一般都要求访问原始资源,所以我们管理资源应该提供访问原始资源的方法

   2.对原始资源的访问可以通过显示转换或者隐式转换,一般来说后者不够安全,但是对客户比较方便。


条款16:成对出现new和delete

  这里是说new一个数组,也要delete一个数组。new一个对象 也delete一个对象

条款17:以独立语句将newed对象植入智能指针

  假设我们这里有个函数

 int priority();

 void processWidget(std::tr1::shared_ptr<Widget>pw,int priority);

这么调用肯定是错误的:processWidget(new Widget,priority());理由很明显了new这个地方出错

 那么我们考虑这样: processWidget(std::tr1::shared_ptr<Widget>(new Widget),priority());这么做可能导致泄漏资源。processWidget(std::tr1::shared_ptr<Widget>(new Widget)的执行首先是new 再构造shared_ptr对象,那么整个函数有三个步骤,前面两个加上一个priority(); 在C++里面执行的步骤是不确定的,他们可能这么做:

1.new

2.priority()

3.shared_ptr...

如果第二个步骤出错,资源泄漏了

所以改进的方法这么做:

std::tr1::shared_ptr<Widget> pw(new Widget);

processWidget(pw,priority());

原创粉丝点击