Chapter 3. Resource Management
Scott说:这儿的resource包括dynamically allocated memory、file descriptors、mutex locks、GUI objects、database connections和network sockets。
“拿了我的给我还回来,吃了我的给我吐出来”……
Item 13 - 17
条款13:Use objects to manage resources






为 了防止程序在delete之前return或因exception中断而无法调用delete,可使用smart pointer auto_ptr(a pointer-like object, its destructor automatically calls delete on what it points to):






auto_ptr 的初始化(也可以用assignment)和resource的分配在同一条语句中完成,其destructor保证了资源会被release。为了保证 在任意时刻只有一个auto_ptr指向同一个资源(这也是其缺陷),当一个auto_ptr被copy给另一auto_ptr对象之后,前一个将被置为 null,这很安全,却也很麻烦。所以在使用auto_ptr指针时要注意copy操作。
如果希望多个指针指向同一资源,可使用引用计数智能指针(reference-counting smart pointer, RCSP)TR1的tr1::shared_ptr指针。
auto_ptr和tr1::shared_ptr都不能用于动态分配数组,因为二者都没有delete[]的用法。boost::scoped_array和boost::shared_array可以分配数组。
条款14:Think carefully about copying behavior in resource-managing classes
条款13主要针对heap-based的资源进行管理,不是所有资源都是heap-based,如mutex。


借用条款13的RAII思想,设计class Lock:










对 于申请类似critical resources,同样可借用RCSP的思想实现,对critical resources的申请和分配进行计数。这里的一个问题是在tr1::shared_ptr析构时如果counter为0将delete掉mutex, 因此可以使用function object实现如下:












条款15:Provide access to raw resources in resource-managing classes
为了能使资源顺利释放,Scott提倡我们使用auto_ptr和tr1::shared_ptr,友情提示:智能指针auto_ptr和tr1::shared_ptr不是指针,而是pointer-like object。因此如果要访问原始资源,需要从其中取出。



说白了,使用auto_ptr和tr1::shared_ptr时,记得它们是对象就行了。
犹如在使用string时,为了得到字符串,你需要这样去用:


除了类似的explicit convertion,也有implicit convertion:











诚 如Scott所言:The best design is likely to be the one that adheres to make interfaces easy to use correctly and hard to use incorrectly.
至于对原始资源访问所造成的contrary to encapsulation,则可以通过design使client取其所取,避其所避。
对 于C/C++程序员来讲,诸如“{”和“}”,“[”和“]”,“"”和“"”,Get和Release,malloc和free,new和delete 这样的搭配我们早已习惯,而对于借助对象的constructor和destructor来完成资源“自动”的分配和释放这样的安全操作显然还需要时间去 适应。
看到这一款,我越来越觉得我的C++基础需要进一步加强。不知道Scott新加的这第三章内容是过于艰涩,还是怎么,总觉得似乎简单,但又没有那么简单,理解的不够深刻。
条款16:Use the same form in corresponding uses of new and delete
这一款在第二版时也是有的,第三版还是加了点内容(尽管不多,却让内容更加易于理解),首先对Scott的态度表示尊敬。
new 和delete不仅仅是要成对出现的问题(当然,这是最根本最重要的问题),而更是要正确的成对出现,就像{}一样。当new被使用时,发生了两件事:内 存分配和constructor(s)调用。当delete被使用时,也发生了两件事:destructor(s)调用和内存回收。问题是你用了什么就要 还回什么,你用了多少就要还回多少。
因此,Scott说:“如果你调用new时用了[],调用delete时也要用[]。如果调用new时没有用[],那调用delete时也不要用[]”。





条款17:Store newed objects in smart pointers in standalone statements






对于初次看到Scott的Resource Management这一章的coders,我不知道大家看过之后能领会多少,反正我自己心里没有底,各种智能指针的使用,想必也和个人的智商成一定正比。总觉得看过之后,再去写代码,难保不是邯郸学步。
这时候,Scott又说:although we're using object-managing resources everywhere here, this call may leak resources……
Before processWidget can be called, then, compilers must generate code to do these three things:
1) Call priority.
2) Execute "new Widget".
3) Call the tr1::shared_ptr constructor.
然而,the call to priority can be performed first, second, or third. 如果不幸的成了这样:
1) Execute "new Widget".
2) Call priority.
3) Call the tr1::shared_ptr constructor.
如果更加不幸的是:the call to priority yields an exception。不要因为这种可能只有不到0.01%,如果被你的客户和老板抓到,那就是100%。


Scott 建议:Store newed objects in smart pointers in standalone statements. Failure to do this can lead to subtle resource leaks when exceptions are thrown.
粗略地看完这一章,Scott带我们实现了Resources Management:
1) Use objects(smart pointers objects) to manage resources: auto_ptr, tr1::shared_ptr and boost::shared_array;
2) Think carefully about copying behavior in resource-managing classes: prohibit copying or reference-count, delete or unlock;
3) Provide access to raw resources in resource-managing classes: explicit or implicit, safer or more convenient;
4) Use the same form in corresponding uses of new and delete: new and delete, new [] and delete [];
5) Store newed objects in smart pointers in standalone statements: avoid exception thrown between new and copy to tr1::shared_ptr.