1、以对象管理内存(Use Objects to manager resources.)
这一条款主要说的是如何进行动态内存申请释放。
RAII原则:
Ø 获得资源后立刻放进管理对象内;
Ø 管理对象运用析构函数确保资源被释放;
我自己也写过一个动态申请释放的类。这个类的一个假设是,一个资源在被申请后会马上被使用,而在函数返回后就需要释放。为此我写了一个基类,每个资源类都要继承这个基类。每个资源子类的构造函数和析构函数都是private,这样就杜绝了new和delete操作。申请新的对象通过类的static函数来实现,不提供释放函数接口。基类中有一个static list,基类的构造函数会将this指针添加到这个list中。基类每隔5个循环就遍历一下list,看有没有待释放对象,如果有,则直接进行释放。
标准程序库auto_ptr类指针对象
应该是一个模板。
std::auto_ptr<Point> pInv(new Point(1));
Point是类指针对象指向的类。
pInv是类指针的变量名称。他后面的()中填写的类指针指向的类的引用。
void r_test()
{
std::auto_ptr<Point> pInv(new Point(1));
pInv->GetX();
}
之后,pInv就可以直接作为Point指针来使用。只不过它是局部变量,在函数返回是会释放。释放的时候,会进行Point的析构操作。
使用auto_ptr一定要防止多个指针指向一个对象,这样会造成多次释放。所以他有一个性质:若通过copy构造函数或者copy赋值函数复制他们,则他们本身会变成NULL,而复制所得指针会获得资源的唯一所有权。
注意:auto_ptr的copy赋值函数和copy构造函数的风险非常大。要少使用。
引用计数型智慧指针(RCSP)
这个在linux好像没有(需要包含头文件#include
注意:
为了防止资源泄漏,请使用RAII(起源获取时机便是初始化时机——资源在构造期间获得,在析构期间释放)对象,他们在构造函数中获得资源,并在析构函数中释放资源。(使用的模板技术)
两个常被使用的RAIIclass分别是tr1::shared_ptr和atuo_ptr。前者通常是较佳选择,因为copy比较直观。若选择atuo_ptr,复制操作会使他(被复制物)指向NULL。
2、在资源管理类中小心copying行为(Think carefully about copying behavior in resource-managing classes.)
如果tr1::shared_ptr和atuo_ptr不适合作为资源管理类,则需要构造自己的资源管理类。
自己设计资源管理类时,也需要遵循RAII原则:
特别需要注意的一个问题是,RAII对象被复制时,会发生什么事情:
1、 禁止复制
2、 对底层资源使用引用计数法(reference count)通常,资源管理类只要内含一个tr1::shared_ptr成员变量,RAII就可以实现reference-counting copying行为。
tr1::shared_ptr默认情况下在删除的时候会delete相应的对象,但是,可以在构造时指定所谓的删除器,那是一个函数或者函数对象(而不是单纯的对象?什么是函数对象?),当应用次数为零时便被调用(此机制并不存在于auto_ptr——他总是将指针删除)。
3、 复制底部资源。也就是进行所谓的深度拷贝。
4、 转移资源的拥有权——就像auto_ptr一样。
注意:
复制RAII对象的时候必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的拷贝行为。
普遍而常见的RAIIclasses copying行为是:抑制copying,施行引用计数法。
3、 在资源管理类中提供对原始资源的访问(Provide access to raw resources in resource-managing classes.)
RAII class需要一个函数可以见RAII classes 对象转化为其所内含的原始资源。
显示转换:
tr1::shared_ptr和auto_ptr都提供get成员函数。用来执行显示转换。
另外,他们都提供了operator->和operator*操作符,可以执行隐式转换。
尽量使用显示转换。
get函数与封装相矛盾,但是问题并不大。因为RAIIclass 主要的作用是为了资源释放。
“设计良好的类,会隐藏用户不需要看到的部分,当备妥客户需要看到的东西。”
注意:
APIs往往要求访问原始资源,所以每一个RAIIclass应该提供一个取得其所管理资源的方法。
对原始资源的访问可能经由显示转换和隐式转换,一般而言显示转换比较安全,但隐式转换相对比较方便。