<Effective C++>读书摘要--Resource Management<一>

1、除了内存资源以外,Other common resources include file descriptors, mutex locks, fonts and brushes in graphical user interfaces (GUIs), database connections, and network sockets. Regardless of the resource, it‘s important that it be released when you‘re finished with it.

<Item 13>Use objects to manage resources

2、In fact, that‘s half the idea behind this Item: by putting resources inside objects, we can rely on C++‘s automatic destructor invocation to make sure that the resources are released.

3、Many resources are dynamically allocated on the heap, are used only within a single block or function, and should be released when control leaves that block or function. The standard library‘s auto_ptr is tailor-made for this kind of situation. auto_ptr is a pointer-like object (a smart pointer) whose destructor automatically calls delete on what it points to. Here‘s how to use auto_ptr to prevent f‘s potential resource leak:

class Investment { ... };            // root class of hierarchy of
                                     // investment types
Investment* createInvestment();  // return ptr to dynamically allocated
                                 // object in the Investment hierarchy;
                                 // the caller must delete it
                                 // (parameters omitted for simplicity)
void f()
{
  Investment *pInv = createInvestment();         // call factory function
  ...                                            // use pInv  此处可能提前return或者抛出异常导致不能delete pInv

  delete pInv;                                   // release object
}
void f()

{
  std::auto_ptr<Investment> pInv(createInvestment());  // call factory
                                                       // function
  ...                                                  // use pInv as
                                                       // before
}                                                      // automatically
                                                       // delete pInv via
                                                       // auto_ptr‘s dtor
auto_ptr解决的是在堆栈(heap)上面分配一个对象后的安全释放问题,它的存在来源于C++对exception的支持。auto_ptr不能存在容器中,多个auto_ptr不能共享同一个对象的使用权,也不能通过它引用一个对象数组并进行释放。现在已经不推荐使用auto_ptr,建议使用unique_ptr.

4、上面代码示例展示了使用对象管理资源的两个重要方面

  • Resources are acquired and immediately turned over to resource-managing objects.

    • In fact, the idea of using objects to manage resources is often called Resource Acquisition Is Initialization (RAII), because it‘s so common to acquire a resource and initialize a resource-managing object in the same statement. Sometimes acquired resources are assigned to resource-managing objects instead of initializing them, but either way, every resource is immediately turned over to a resource-managing object at the time the resource is acquired.
  • Resource-managing objects use their destructors to ensure that resources are released.

    • Things can get tricky when the act of releasing resources can lead to exceptions being thrown, but that‘s a matter addressed by Item 8, so we‘ll not worry about it here.

5、Because an auto_ptr automatically deletes what it points to when the auto_ptr is destroyed, it‘s important that there never be more than one auto_ptr pointing to an object. If there were, the object would be deleted more than once, and that would put your program on the fast track to undefined behavior. To prevent such problems, auto_ptrs have an unusual characteristic: copying them (via copy constructor or copy assignment operator) sets them to null, and the copying pointer assumes sole ownership of the resource! STL containers require that their contents exhibit "normal" copying behavior, so containers of auto_ptr aren‘t allowed.

std::auto_ptr<Investment>                 // pInv1 points to the
  pInv1(createInvestment());              // object returned from
                                          // createInvestment

std::auto_ptr<Investment> pInv2(pInv1);   // pInv2 now points to the
                                          // object; pInv1 is now null

pInv1 = pInv2;                            // now pInv1 points to the
                                          // object, and pInv2 is null

6、An alternative to auto_ptr is a reference-counting smart pointer (RCSP). An RCSP is a smart pointer that keeps track of how many objects point to a particular resource and automatically deletes the resource when nobody is pointing to it any longer. As such, RCSPs offer behavior that is similar to that of garbage collection. Unlike garbage collection, however, RCSPs can‘t break cycles of references (e.g., two otherwise unused objects that point to one another).

TR1‘s tr1::shared_ptr (see Item 54) is an RCSP, so you could write f this way:

void f()
{
  ...
  std::tr1::shared_ptr<Investment>
    pInv(createInvestment());             // call factory function

  ...                                     // use pInv as before
}                                         // automatically delete
                                          // pInv via shared_ptr‘s dtor

tr1::shared_ptr 在用法上与auto_ptr 差不多,但是赋值时表现与auto_ptr 不同。

void f()
{
  ...
  std::tr1::shared_ptr<Investment>          // pInv1 points to the
    pInv1(createInvestment());              // object returned from
                                            // createInvestment

  std::tr1::shared_ptr<Investment>          // both pInv1 and pInv2 now
    pInv2(pInv1);                           // point to the object

  pInv1 = pInv2;                            // ditto — nothing has
                                            // changed
  ...
}                                           // pInv1 and pInv2 are
                                            // destroyed, and the
                                            // object they point to is
                                            // automatically deleted

Because copying tr1::shared_ptrs works "as expected," they can be used in STL containers and other contexts where auto_ptr‘s unorthodox copying behavior is inappropriate.

7、Both auto_ptr and tr1::shared_ptr use delete in their destructors, not delete []. (Item 16 describes the difference.) That means that using auto_ptr or TR1::shared_ptr with dynamically allocated arrays is a bad idea, though, regrettably, one that will compile:

std::auto_ptr<std::string>                       // bad idea! the wrong
  aps(new std::string[10]);                      // delete form will be used

std::tr1::shared_ptr<int> spi(new int[1024]);    // same problem

在C++标准库中没有针对数组的智能指针,TR1中也没有,可以用vector或者string代替数组。 If you still think it would be nice to have auto_ptr- and TR1::shared_ptr-like classes for arrays, look to Boost (see Item 55). There you‘ll be pleased to find the boost::scoped_array and boost::shared_array classes that offer the behavior you‘re looking for.

8、Things to Remember

  • To prevent resource leaks, use RAII objects that acquire resources in their constructors and release them in their destructors.
  • Two commonly useful RAII classes are TR1::shared_ptr and auto_ptr. tr1::shared_ptr is usually the better choice, because its behavior when copied is intuitive. Copying an auto_ptr sets it to null.

<Item 14>Think carefully about copying behavior in resource-managing classes.

9、what should happen when an RAII object is copied? Most of the time, you‘ll want to choose one of the following possibilities:

class Lock {
public:
  explicit Lock(Mutex *pm)
  : mutexPtr(pm)
  { lock(mutexPtr); }                          // acquire resource

  ~Lock() { unlock(mutexPtr); }                // release resource
private:
  Mutex *mutexPtr;
};
  • Prohibit copying

    • In many cases, it makes no sense to allow RAII objects to be copied. This is likely to be true for a class like Lock, because it rarely makes sense to have "copies" of synchronization primitives. 参考item6具体实现如下
class Lock: private Uncopyable {            // prohibit copying — see
public:                                     // Item 6
 ...                                        // as before
};
  • Reference-count the underlying resource.

    • Sometimes it‘s desirable to hold on to a resource until the last object using it has been destroyed. When that‘s the case, copying an RAII object should increment the count of the number of objects referring to the resource. This is the meaning of "copy" used by tr1::shared_ptr.Fortunately, tr1::shared_ptr allows specification of a "deleter" — a function or function object to be called when the reference count goes to zero. (This functionality does not exist for auto_ptr, which always deletes its pointer.) The deleter is an optional second parameter to the tr1::shared_ptr constructor, so the code would look like this
class Lock {
public:
  explicit Lock(Mutex *pm)       // init shared_ptr with the Mutex
  : mutexPtr(pm, unlock)         // to point to and the unlock func
  {                              // as the deleter
    lock(mutexPtr.get());   // see Item 15 for info on "get"
  }
private:
  std::tr1::shared_ptr<Mutex> mutexPtr;    // use shared_ptr
};                                         // instead of raw pointer
    • In this example, notice how the Lock class no longer declares a destructor. That‘s because there‘s no need to. Item 5 explains that a class‘s destructor (regardless of whether it is compiler-generated or user-defined) automatically invokes the destructors of the class‘s non-static data members. 最好加上注释说明不是忘记在析构函数中释放锁资源。
  • Copy the underlying resource.

    • That is, copying a resource-managing object performs a "deep copy."
  • Transfer ownership of the underlying resource

10、Things to Remember

  • Copying an RAII object entails copying the resource it manages, so the copying behavior of the resource determines the copying behavior of the RAII object.
  • Common RAII class copying behaviors are disallowing copying and performing reference counting, but other behaviors are possible.
时间: 2024-10-27 13:24:19

<Effective C++>读书摘要--Resource Management<一>的相关文章

&lt;Effective C++&gt;读书摘要--Designs and Declarations&lt;三&gt;

<Item 22> Declare data members private 1.使数据成员private,保持了语法的一致性,client不会为访问一个数据成员是否需要使用括号进行函数调度,还是不使用括号直接访问成员而纠结. 2.使数据成员private,if you use functions to get or set its value, you can implement no access, read-only access, and read-write access. Heck

Effective STL读书摘要(一)

一直在用STL,认为对STL也有一些理解,比如比较函数怎么写,什么情况下用什么容器效率高,但是当你读过Effective STL之后才知道这远远不够,之前的代码还有很多可以优化的空间,下面我会罗列一些映像比较深的点,比较偏向代码因为这样可以方便以后的调用.这里是到Item29,余下的留下次看. 1) 检查容器是否为空 if(c.empty()){}   better than if(c.size()==0){} 2)如果能用批量操作函数就不要用循环来做 批量操作可以提高效率,要有能用批处理尽量批

&lt;Effective C++&gt;读书摘要--Inheritance and Object-Oriented Design&lt;一&gt;

1. 3.

&lt;Effective C++&gt;读书摘要--Designs and Declarations&lt;二&gt;

<Item 20> Prefer pass-by-reference-to-const to pass-by-value 1.By default, C++ passes objects to and from functions by value (a characteristic it inherits from C). Unless you specify otherwise, function parameters are initialized with copies of the

&lt;Effective C++&gt;读书摘要--Templates and Generic Programming&lt;一&gt;

1.The initial motivation for C++ templates was straightforward: to make it possible to create type-safe containers like vector, list, and map. Ultimately, it was discovered that the C++ template mechanism is itself Turing-complete: it can be used to

&lt;Effective C++&gt;读书摘要--Ctors、Dtors and Assignment Operators&lt;二&gt;

<Item 9> Never call virtual functions during construction or destruction 1.you shouldn't call virtual functions during construction or destruction, because the calls won't do what you think, and if they did, you'd still be unhappy. If you're a recov

Effective Objective-C 读书笔记

一本不错的书,给出了52条建议来优化程序的性能,对初学者有不错的指导作用,但是对高级阶段的程序员可能帮助不是很大.这里贴出部分笔记: 第2条: 使用#improt导入头文件会把头文件的内容全部暴露到目标文件中,而且如果两个类之间存在循环引用则会出现编译错误,所以要尽量使用@class进行类声明. 如果需要实现一个协议,则必须#improt这个协议的头文件,所以可以将协议单独定义在一个.h文件当中.如果这个协议是代理模式协议的一部分,即需要与类捆绑使用才有实际意义,则建议定义在类当中,并以类名为前

Effective Java 读书笔记(2创建和销毁对象)

第一章是引言,所以这里不做笔记,总结一下书中第一章的主要内容是向我们解释了这本书所做的事情:指导Java程序员如何编写出清晰.正确.可用.健壮.灵活和可维护的程序. 2.1考虑用静态工厂方法代替构造器 静态工厂方法与构造器相比有四大优势: (1)静态工厂方法有名称,具有适当名称的静态工厂方法易于使用.易于阅读: (2)不必每次在调用它们的时候都创建一个新的对象: (3)可以返回原返回类型的任何子类型的对象: (4)在创建参数化类型实例的时候,它们使代码变得更加简洁. 同时静态工厂方法也有两大缺点

Effective java读书札记第一条之 考虑用静态工厂方法代替构造器

对于类而言,为了让客户端获取它资深的一个实例,最常用的方法就是提供一个共有的构造器.还有一种放你发,也应该子每个程序员的工具箱中占有一席之地.类可以提供一个共有的静态 工厂方法,它只是返回类的实例的静态方法. 类可以通过静态工厂方法类提供它的客户端(对象),而不是通过构造器.提这样做的好处有: 1.静态工厂方法与构造器不同的第一大优势在于,它们有名称.比如构造器BigInteger(int,int,Random)返回的BigInteger可能为素数,如果用名为BigInteger.probabl