最经常使用的资源就是,new出来的内存,即动态分配内存,此外还有数据库链接,网络sockets等等。重要的是,一旦使用完这些资源,必须给系统。数据库
所谓,用对象管理资源,就是利用对象销毁时,自动调用析构函数,在析构函数内释放这些资源,从而在某种程度上达到自动释放资源的目的数组
RAII:Resource Acquisiton Is Inintialization.取得资源时便初始化,即得到资源的同时,就使用该资源初始化管理对象。网络
PS:《Effective C++》关于智能指针的建议是关于auto_ptr,和tr1::shared_ptr的,而在C++11新标准中,auto_ptr能够由unique_ptr代替, tr1::shared_ptr可使用标准库的std::shared_ptr中。socket
本质问题是,当RAII被复制时,其管理的资源该怎么处理。ide
1.禁止复制。像是C++中的输入输出流,就是禁止复制。经过两种方法能够达到禁止复制函数
拷贝函数声明为private,且不须要实现ui
C++ 11:在拷贝函数的声明后加上“=delete”spa
2.对底层使用“引用计数法”。《Effective》内使用的是tr1::shared_ptr,但如今有了更好的选择std::shared_ptr指针
3.复制底部资源。这就须要自定义拷贝函数,达到深度拷贝的功能orm
4.转移底部资源的拥有权。自始至终,只能有一个对象管理类。《Effective》使用的是auto_ptr,C++ 11新标准中由unique_ptr,能比auto_ptr实现更多特性
在某些状况,必须直接访问原始资源。例如 C API 没有class的概念
1. 显式。RAII提供一个成员函数,返回原始资源。如shared_ptr和unique_ptr,都提供get()函数,返回指向资源的原始指针
2. 隐式。为RAII提供到原始资源的隐式转换,即重载operator()。
class Font{ public: ... operator FontHandle() const; private: FontHandle f; };
然而在复制Font对象时,可能就会出现问题
Font f1(getFont()); FontHandle f2 = f1;
在复制的过程当中,f1被隐式转换成FontHandle,而后复制给f2。也许f2会复制一份副本,也许f2直接指向f1的资源。若是是后者,一旦f1销毁,资源被释放,f2就成为相似空悬指针。
new单一对象,使用delete销毁
new对象数组,使用delete[] 销毁对象数组
转换为代码就是
T* tPtr = new T(); shared_ptr<T> p(tPtr);
对于这样一个函数
void processWidget(shared_ptr<Widget> pw, int priority); int priority();
如今调用
processWidget(shared_ptr<Widget>(new Widget()), priority());
C++是不能肯定以上两个参数的方法,是按什么顺序调用的。若是出现这样一种状况,先调用priority(),但调用的过程当中出现异常,这就致使智能指针没用正确初始化。在对processWidget的调用过程当中,就出现的资源泄露。
注意这样一段代码
Widget * tPtr = new Widget (); processWidget(shared_ptr<Widget>(tPtr), priority()); Widget widget = *tPtr;//tPtrz指向的内存已被释放,tPtr成为空悬指针
对于此的建议是,既然用内置指针去初始化智能指针,那就不要使用内置指针
或者,一开始就使用智能指针,内置指针仅用做初始化(临时对象)
shared_ptr<Widget> pw(new T()); processWidget(pw, priority());