条款13 以对象管理资源
RAII对象:
为防止资源泄漏,使用RAII对象 它们在构造函数中获得资源并在析构函数中释放资源
条款14 在资源管理类中小心coping行为
复制底层资源:复制资源管理的对象 应该同时也复制其所包覆的资源 复制资源管理对象时进行的是深拷贝
普遍而常见的RAII行为是:阻止拷贝、运用引用计数法。 不过其他行为也都可能被实现。
条款15 在资源管理类中提供对原始资源的访问
智能指针提供get成员函数 用来返回智能指针内部的原始指针(的副本);智能指针也重载了指针取值操作符(operator->
和operator *
),允许隐式转化至底部原始指针。
如果觉得每一次都需要调用get
非常麻烦 可以令为资源管理类提供隐式转换函数operator type
:
class Font{
public:
...
operator FontHandle()const {return f;}
};
但是隐式类型转换可能会引发问题
Font f1(getFont());
...
FontHandle f2=f1;//本意是拷贝一个Font对象 但是隐式转换为FontHandle才复制它
f1和f2都管理一个FontHandle,如果f1被销毁 那么f2因此称为“虚吊的”。
对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换比较安全,但隐式转换对客户比较方便
条款16 成对使用new和delete时要采用相同形式
当使用new
时,首先内存会通过operator new
分配出来,然后针对此内存会调用一个或多个构造函数;
当使用delete
时,首先针对此内存会调用一个或多个析构函数,然后内存才会通过oeprator delete
释放。所以delete的最大问题在于:即将被删除的内存之内究竟有多少对象?这决定了有多少个析构函数被调用
条款17 以独立语句将newed对象置入智能指针
**shared_ptr**
需要原始指针的构造函数是**explicit**
的,无法进行隐式类型转换,将得自new Widget
的原始指针转换为process所要求的shared_ptr
。
二者 一个能通过编译,一个不能通过编译。说明单一参数的构造函数提供了一个隐式类型转换的方式(将传参类型转换为类类型),如果构造函数声明为**explicit**
那么这种转换将不复存在。
HINT:cppreference写明,一个只有一个参数且没有被声明为explicit
的构造函数称为转换构造函数,而且这种构造不同于explicit的构造函数,这种构造也会应用于拷贝初始化。它提供了隐式的类型转换。
//函数声明
int priority();
void process(std::shared_ptr<Widget>pw,int priority);
process(new Widget,priority()); //无法通过编译
process(std::shared_ptr<Widget>((new Widget),priority())//可以通过 但可能泄漏资源
C++编译器核算函数参数的顺序是不固定的!
如果按照如下顺序:
①执行 new Widget
②调用priority
③调用std::shared_ptr构造函数
如果对priority的调用产生异常,new Widget返回的指针将会遗失,因为尚未被置入std::shared_ptr内
解决方法:使用分离语句构造智能指针
std::share_ptr<Widget>pw(new Widget);
process(pw,priority()); //大功告成!
编译器对于“跨越语句的各项操作”没有重新排列的自由 。只有在一条语句内部才有重排的自由度。