Effective C++看书笔记(3):资源管理

资源管理

  • 13:以对象管理资源
  • 14:在资源管理类中小心copying行为
  • 15:在资源管理类中提供对原始资源的访问
  • 16:成对使用new和delete时要采取相同形式
  • 17:以独立语句将newed对象置入智能指针

13:以对象管理资源

void f()
{
    A* a=createA();
    
    
    delete a;
}

这样写实际上很多情况都删除不了,比如提前退出了函数,抛出了异常,后续维护代码修改为提前return 。

所以利用对象的析构来管理内存资源

例子auto_ptr

void f()
{
    std::auto_ptr<A> ptr(createA());
    ......
}

这就是RAII(Resource Acquisition Is Initialization)

但是需要注意指针不要指向同一个对象。不然会删除多次。

为了预防这个问题,auto_otr有一个不寻常的性质:若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权。

std::auto_ptr<A> ptr(createA());
std::auto_ptr<A> ptr2(ptr);//ptr会被设置为Null
std::auto_ptr<A> ptr=ptr2;//ptr2会被设置为null

这样的性质导致了一些局限性,有时候我们就是需要多个指针指向一个对象,然后只释放一次。

替代方案就是shared_ptr

void f()
{
    std::tr1::shared_ptr<A> ptr(createA());
    ......
}

但是它打破不了环形引用。

auto_ptr和shared_ptr(一般都用这个),两者都在其析构函数内做delete而不是delete[]动作,所以不要在动态分配得到的array身上使用auto_ptr或tr1::shared_ptr

vector和boost::scoped_array和boost::shared_array都可以替代array。

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

如果资源不是在堆上,那么auto_ptr和tr1::shared_ptr就不适合了。

这种情况就需要自己建立资源管理类

例如

针对Mutex的lock和unlock,建立资源管理类Lock

class Lock{
public:
    explicit Lock(Mutex* pm):mutenPtr(pm)
    {
        lock(mutexPtr);
    }
    
    ~Lock(){unlock(mutexPtr);}
    private:
    Mutex *mutexPtr;
};

这样调用来使用

Lock m1(&mutex);

但是如果Lock被复制怎么办?

Lock m1(&m);
Lock m2(m1);

大多数时候有两种选择

  • 禁止复制RAII对象,很多时候允许复制并不合理。即把copying操作声明为private
  • 对底层资源祭出引用计数法:有时候希望资源被最后一个使用者销毁。这种情况复制RAII对象,应该把底层资源引用计数加1。此时即可使用tr1::shared_ptr。
    • 但是shared_ptr默认行为是当引用次数为0是删除其所指物,而不是我们想要的unlock。
    • 但我们可以传入一个函数对象即可让引用计数为0是,它执行我们的行为。
class Lock{
public:
    explicit Lock(Mutex* pm):mutenPtr(pm,unlock)
    {
        lock(mutexPtr.get());
    }
    
    private:
    std::tr1::shared_ptr<Mutex> mutexPtr;
};

其它方式相对不常见

  • 复制底部资源:深拷贝一份
  • 转移底部资源的拥有权:

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

把智能指针转化为真实资源(普通指针)可以调用shared_ptr和auto_ptr的get成员函数。

也可以隐式(操作符->和*)这样来使用。

但是显式转换更受欢迎,不容易出错。

16:成对使用new和delete时要采取相同形式

delete单一对象就是delete。

delete对象数组需要delete []。两个都必须严格对应原来的形式。

  • 你写的class用一个指针指向动态分配的内存,就必须把所有对象构造出视乎,这样才能delelte析构所有的对象。
  • 最好尽量不要对数组形式做typedef动作。

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

不要一句把new对象,智能指针构造函数放到一个地方去,而应该拆分。否则可能出现异常导致资源泄露

processA(std::tr1::shared_ptr<A>(new A),priority());//这是错误的。

//这是正确的
std::tr1::shared_ptr<A> pw(new A)
    processA(pw,priority())

原因是执行顺序可能重排序。

错误的这一句可能是

  • new A
  • priority
  • new A放入智能指针

priority出现异常了,new A对象就丢失了。

你可能感兴趣的:(C++语言,c++,笔记,开发语言)