您的位置:首页 > 编程语言 > C语言/C++

Effective C++第三章-资源管理-1

2017-06-30 14:38 351 查看

C++的资源:

动态分配内存

文件描述器

数据库连接

网络sockets

互斥锁

图形界面中的字型和笔刷

以对象管理资源(又称为资源取得时机便是初始化时机,resource acquisition is initialization,RAII)

单纯依靠调用端执行delete语句是行不通的:

一般调用端函数使用了函数(Create函数)返回的对象后,有责任删除之。但在以下情况下可能使得调用端函数来不及删除

一个过早的return语句

一个存在continue和goto语句的循环

某个语句抛出异常

为确保Create函数返回的资源总是被释放,我们需要将资源放进对象内,当控制流离开调用端函数,该对象的析构函数会自动释放资源

例1:auto_ptr

Header: < memory >

Namespace: std

是一个类指针对象,也就是智能指针,其析构函数自动对其所指对象调用delete

void f()
{ std::auto_ptr<Investment> pInv(createInvestment());
//利用create函数获得资源后立即放进对象pInv
...
}//经由auto_ptr的析构函数自动删除pInv


PS:对象被删除一次以上,会使程序出现“未定义行为”

诡异的复制行为:若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权,因此,受auto_ptr管理的资源必须绝对没有一个以上的auto_ptr同时指向它。

std::auto_ptr<Investment> pInv1(createInvestment());
std::auto_ptr<Investment> pInv2(pInv1);//现在pinv2指向对象,pInv1被设为NULL
pInv1 = pInv2; //现在pInv1指向对象,pInv2被设为NULL


例2:引用计数型智慧指针(reference-counting smart pointer,RCSP)shared_ptr

Header: < memory >

Namespace: std::tr1

也是智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。

void f()

{

std::tr1::shared_ptr pInv(createInvestment());

//利用create函数获得资源后立即放进对象pInv,shared_ptr是一个RCSP



}//经由shared_ptr的析构函数自动删除pInv

RCSP无法打破环状引用(例如两个其实已经没被使用的对象彼此互指,因而好像处于“被使用”状态)。

缺省行为是“当引用次数为0时删除其所指”,std::tr1::shared_ptr也允许指定“删除器”,是一个函数或函数对象,当引用次数为0时便被调用,删除器对std::tr1::shared_ptr构造函数而言是可有可无的地儿参数(此机能不存在于auto_ptr,它总是将其指针删除)

class Lock{
public:
explicit Lock(Mutex* pm):mutexPtr(pm,unlock){}//以unlock函数为删除器
private:
std::tr1::shared_ptr<Mutex> mutexPtr;
};


复制

std::tr1::shared_ptr<Investment> pInv1(createInvestment());
std::tr1::shared_ptr<Investment> pInv2(pInv1);//pinv2,pInv1指向同一对象
pInv1 = pInv2; //pinv2,pInv1指向同一对象


在auto_ptr和shared_ptr的析构函数内做delete而不是delete[],因此虽然可以通过编译,在动态分配而得的array身上使用是馊主意。

在复制资源管理对象时,进行的是“深度拷贝”

对于非heap-based资源,像auto_ptr和tr1::shared_ptr智能指针往往不适合作为资源掌管者

PS : TR1(Technical Report 1)是一份规范,描述加入C++标准程序的诸多新技能大多数TR1机能是以Boost的工作为基础的。TR组件位于std::tr1命名空间中。大多数TR1机能是以Boost的工作为基础的。TR组件位于std::tr1命名空间中

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

举例:

std::tr1::shared_ptr<Investment> pInv(createInvestment());
...
int fun(const Investment* pi);
...
int x = fun(pInv);//错误,所需参数是Investment*指针,但是传递的是tr1::shared_ptr<Investment>对象


解决方法:

显式转换(比较安全)

tr1::shared_ptr和auto_ptr都提供一个get成员函数执行显式转换。也就是它会返回智能指针内部的原始指针(的复件):

int x = fun(pInv.get());


隐式转换(对客户比较方便)

同所有智能指针一样,tr1::shared_ptr和auto_ptr也重载指针取值操作符(operator->和operator*),它们允许隐式转换至底部原始指针:

class Investment{
public:
bool isfun() const;
...
};
Investment* createInvestment();
std::tr1::shared_ptr<Investment> pi1(createInvestment());
bool isf1 = !(pi1->isfun());
...
std::tr1::shared_ptr<Investment> pi1(createInvestment());
bool isf1 = !((*pi1).isfun());


提供隐式转换函数

相关链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息