【effective c++】资源管理

以对象管理资源的观念常被称为“资源取得时机便是初始化时机”(RAII)

auto_ptr被销毁时会自动删除它所指之物,所以一定要注意别让多个auto_ptr同时指向同一对象,否则对象会被删除多次,行为未定义

auto_ptr有一个性质:若通过拷贝构造函数或拷贝赋值运算符复制它们,它们会变成NULL,而复制所得的指针将取得资源的唯一拥有权

class Investment
{
private:
    double value;
public:
    Investment(double val):value(val){}
    double getValue()
    {
        return value;
    }
};

Investment* createInvestment(double val)
{
    return new Investment(val);
}

int main()
{
    auto_ptr<Investment> pInv1(createInvestment(3.0));
    cout << pInv1->getValue() << endl;
    auto_ptr<Investment>pInv2(pInv1);
    cout << pInv1->getValue() << endl;//出错,pInv1为NULL
}

可以用shared_ptr来代替auto_ptr,shared_ptr有一个缺点:无法打破环状引用,若两个其实已经没被使用的对象彼此互指,就好像还处在被使用的状态

auto_ptr和shared_ptr两者都在其析构函数内做delete而不是delete[]动作,所以在动态分配而得的array身上使用auto_ptr或shared_ptr是个馊主意

总结:

1.为防止资源泄露,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源

2.两个常被使用的RAII classes是shared_ptr和auto_ptr,前者是更好的选择(两者均用于管理heap上资源)

 

use shared_ptr with an array: https://stackoverflow.com/questions/13061979/shared-ptr-to-an-array-should-it-be-used

template<typename T >
struct array_deleter {  // 仿函数
  void operator ()( T const * p) {
      cout << "deleting" << endl;
      delete[] p;
  }
};

int main()
{
    std::shared_ptr<int> sp( new int[10], array_deleter<int>() );

    system("pause");
    return 0;
}

 

 


 

class Lock
{
public:
    explicit Lock(mutex* pm) :mutexPtr(pm)
    {
        mutexPtr->lock();
    }
    ~Lock()
    {
        mutexPtr->unlock();
    }
private:
    mutex *mutexPtr;
};
----------------------------------------------------------------------------
//对底层资源采用引用计数
class Lock
{
public:
    explicit Lock(mutex* pm) :mutexPtr(pm,pm->unlock)
    {
        mutexPtr.get()->lock();
    }
private:
    tr1::shared_ptr<mutex> mutexPtr;
};

shared_ptr允许指定删除器(deleter),这是一个函数或函数对象,当引用次数为0时便被调用(此机能并不存在于auto_ptr,它总是将指针删除)


在资源管理类中提供对原始资源访问的方法(即将RAII class对象转换为其所内含的原始资源):显式转换和隐式转换

显式转换:shared_ptr 和auto_ptr提供get成员函数,用来执行显式转换,返回智能指针内部的原始指针

隐式转换:shared_ptr和auto_ptr重载了指针取值操作符(operator->和operator*),它们允许隐式转换至底部原始指针

RAII class内的返回原始资源的函数与封装性发生矛盾,不过这并不要紧。RAII class并不是为了封装某物存在,它们的存在是为了确保资源释放会发生


 

成对使用new和delete时要采取相同形式。当class含有一个指针指向动态分配内存,并提供多个构造函数时,这种情况下你必须在所有构造函数中使用相同形式的new将指针成员初始化。如果没这样做,无法确定在析构函数中使用什么形式的delete。

shared_ptr构造函数是个explicit构造函数,无法进行隐式转换

以独立语句将newed对象存储于智能指针内,如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。在资源被创建和资源被转换为资源管理对象两个时间点之间可能发生异常干扰(条款17)


 

shared_ptr与weak_ptr智能指针均是C++ RAII的一种应用,可用于动态资源管理

shared_ptr基于“引用计数”模型实现,多个shared_ptr可指向同一个动态对象,并维护了一个共享的引用计数器,记录了引用同一对象的shared_ptr实例的数量。当最后一个指向动态对象的shared_ptr销毁时,会自动销毁其所指对象(通过delete操作符)。

shared_ptr的默认能力是管理动态内存,但支持自定义的Deleter以实现个性化的资源释放动作。

weak_ptr用于解决“引用计数”模型循环依赖问题,weak_ptr指向一个对象,并不增减该对象的引用计数器

weak_ptr用于配合shared_ptr使用,并不影响动态对象的生命周期,即其存在与否并不影响对象的引用计数器。

weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象。

提供了expired()与lock()成员函数,前者用于判断weak_ptr指向的对象是否已被销毁,后者返回其所指对象的shared_ptr智能指针(对象销毁时返回”空“shared_ptr)。

 

posted @ 2016-07-29 19:46  合唱团abc  阅读(264)  评论(0编辑  收藏  举报