Effective C++ rule 14 在资源管理对象中处理好copy行为

来源:互联网 发布:通联数据 公司怎样 编辑:程序博客网 时间:2024/06/05 22:32

前言

上节说到,为了能够方便的管理资源,达到自动释放资源的目的,我们提出了使用栈对象管理资源的思想。其中,上一节我们重点介绍了如何处理动态内存资源。但是处理动态分配的内存资源外,还有一些其他的资源,例如 互斥锁/信号量,文件描述符,等等,这些东西有自己的特有的资源管理需求。互斥锁需要在离开临界区时及时unlock,而不是像内存管理那么delete掉。这个时候就需要我们自己定制资源管理类了。

然后,自己定制资源管理类时,要特别注意类的复制函数的行为。

举个例子

Code1.1

#include <stdio.h>#include <stdlib.h>class Lock{public:    Lock(mutex *pm) :mutexPtr(pm)    {        lock(pm);    }    ~Lock()    {        unlock(mutexPtr);    }private:    mutex *mutexPtr;};

这个Lock简单的对互斥锁进行管理,能够实现互斥锁在离开作用域是的自动解锁。但是如果存在这样的语句:

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

会发生怎么样的事情呢?默认的编译器会将m1的mutexPtr指针复制给m2的mutexPtr,这样就会有两个对象去指向互斥锁m。这个时候将会出现m1与m2被回收后,m解锁两次的问题。

然而,我们并不希望发生这样的事情,那么这个时候就需要我们手动的指定复制函数行为,包括复制构造函数以及赋值运算符。我们可以把Lock设计为无法复制的。例如:
Code1.2

#include <stdio.h>#include <stdlib.h>class Lock{public:    Lock(mutex *pm) :mutexPtr(pm)    {        lock(pm);    }    ~Lock()    {        unlock(mutexPtr);    }private:    Lock(const Lock & rhs)    {        ;    }    Lock& operator=(const Lock&rhs)    {        ;    }private:    mutex *mutexPtr;};

常见的处理方式

一般来说,在为资源管理对象编写复制函数(复制构造函数,赋值运算)时主要有以下的策略:

禁止复制。

如果复制资源是不合理的,那么我们可以禁止资源管理对象之间的复制。这主要是将类的复制构造函数和赋值运算符定义为private即可。例如Code1.2所示的方法。

使用“引用计数法”

有时候,我们希望保有资源,直到它的最后一个使用者被销毁时。举个应用场景:某些动态分配的内存,可能会有多个指针指向同一个动态资源,大部分时候我们希望直到指针都不在指向该资源是再释放该资源。这个时候就需要使用“引用计数法”。这个使用shared_ptr作为资源管理器的其中一个变量即可。
Code1.3

#include <stdio.h>#include <stdlib.h>#include <iostream>#include <xstddef>#include <memory>using namespace std;class Lock{public:    explicit Lock(mutex *pm) :mutexPtr(pm, unlock)    {        lock(pm);    }    ~Lock()    {        unlock(mutexPtr);    }private:    shared_ptr<mutex> mutexPtr;};

允许复制,而且支持深度复制

这个比较好理解,进行深度复制。

转移控制权

有时,我们允许资源类间的复制,但是复制意味资源控制权的转移,比如auto_ptr指针的做法。例如:
Code1.4

#include <stdio.h>#include <stdlib.h>class Lock{public:    Lock(mutex *pm) :mutexPtr(pm)    {        lock(pm);    }    ~Lock()    {        unlock(mutexPtr);    }    Lock(Lock & rhs)    {        if (this == &rhs) return ;        mutex * temp = rhs.mutexPtr;        rhs.mutexPtr = NULL;        mutexPtr = temp;    }    Lock& operator=(Lock&rhs)    {        if (this == &rhs) return *this;        mutex * temp = rhs.mutexPtr;        rhs.mutexPtr = NULL;        mutexPtr = temp;        return *this;    }private:    mutex *mutexPtr;};

总结

在自己编写资源管理类的时候,要特别关注copy函数的编写,要弄清楚所管理的资源需要什么样的copy行为。

阅读全文
0 0
原创粉丝点击