所谓资源,就是一旦用了,就要还给系统。C++中最常见的就是动态分配内存。其他资源还包括文件描述符、互斥锁等等
1.条款13:以对象管理资源
把资源放到对象内,那么就可以通过C++的析构函数自动调用的机制去确保资源被释放。这种观念常被称为RAII(资源取得时机就是初始化时机)
智能指针shared_ptr就是这种思想的实现:
std::shared_ptr<Cat> cat;
以上的代码声明了一个Cat类型的共享指针,shared_ptr会确保Cat的销毁
总结: 把资源放到对象内,那么就可以通过C++的析构函数自动调用的机制去确保资源被释放。,而shared_ptr则是这种想法的一个优雅的实现
2.条款14:在资源管理类中小心copying行为
RAII对象必须一并复制它所管理的类,所以资源的copying行为决定RAII对象的copying行为。RAII对象的复制我们一般有两种需求:
- 禁止复制,可以参照条款6实现,或者参照 C++11,声明delete显式删除拷贝构造函数
- 希望底层资源能够在最后一个使用者不使用后才删除:施行指针计数法,把资源声明为shared_ptr
总结: - 复制RAII对象必须复制它的所有资源,所以资源的copying行为决定RAII对象的copying行为
- 普遍而常见的RAII拷贝行为是抑制拷贝、施行指针计数法
3.条款15:在资源管理类中提供对原始资源的访问
API往往要求访问原始资源,所以每一个RAII类应该提供一个取得原始资源的,主要有了两种方式:
- 显式转换
- 在shared_ptr内可以利用get函数显式获取资源
std::shared_ptr<Cat> cat;
cat.get() //显式获取资源
2. 在自己实现类中则是
FontHandle getFont() //这是C语言的API函数
class Font{
public:
FontHandle get() const{return f;}
private:
FontHandle f;
}
- 隐式转换:
FontHandle getFont() //这是C语言的API函数
class Font{
public:
operator FontHandle() const{return f;}
private:
FontHandle f;
}
显式转换比较安全,隐式转换比较方便。
总结:
- API往往要求访问原始资源,所以每一个RAII类应该提供一个取得原始资源的,主要有了两种方法,显式转换和隐式转换,显式转换比较安全,隐式转换方便用户。
4.条款16:成对使用new和delete时要采取相同形式
C++ new和delete 有两种形式
- new或者delete一个对象
string * hello= new string("hello");
delete hello;
- new或者delete一个对象组成的数组
string * hellos = new string[100]
delete hellos [];
如果对上述两种形式混用,会出现错误,因需要匹配使用。
总结: C++ new和delte 有两种形式:new或者delete一个对象,new或者delete一个对象组成的数组。需要搭配使用
5.以独立语句将newed对象置入智能指针
在使用只能指针的时候需要使用独立的语句子将newed对象置入智能指针。比如有如下的函数
int eat();
void dailyLife(shared_ptr<Cat> cat , int eaten);
用户可能会这样调用函数:
dailyLife(shared_ptr<Cat>(new Cat), eat());
C++此时需要执行:
- Cat构造
- shared_ptr构造
- eat函数调用
而在C++下,这三个函数的先后顺序不一定,如果顺序是下面这样: - Cat构造
- eat函数调用
- shared_ptr构造
则会发生问题:如果eat调用函数发生异常,那么Cat构造返回的指针将会丢,因为此时Cat指针尚未被shared_ptr管理起来
因此正确的在做法是以独立语句将newed对象置入智能指针:
shared_ptr<Cat> cat (new Cat);
dailyLife(cat, eat());
总结: 以独立语句将newed对象置入智能指针
标签:Effective,RAII,C++,资源管理,new,shared,ptr,delete From: https://www.cnblogs.com/shell-zlj/p/18197045