• effective c++:资源管理


    对象管理资源

    createInvestment 函数作用时创建一个invest对象:

    void f()
    {
      Investment *pInv = createInvestment(); // call factory function
      ... // use pInv
      delete pInv; // release object
    }

    既然f函数中创建对象,销毁对象的责任也应该由它来承担,但是如果“……”区域出现异常或return提前执行,delete将被跳过,从而造成严重的内存泄露,为了确保无论发生什么情况createInvestment返回的对象始终能记得被销毁,我们就需要将他放入一个对象内,析构函数会自动的释放资源,c++标准库提供auto_ptr,即智能指针,他是个类指针对象,析构函数自动对他调用delete:

    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时要注意,一旦让多个auto_ptr指向同一个对象,资源只存放在最后指向的指针中,其他指针均为null,所以auto_ptr在实际使用时局限性很大,c++11已经舍弃了这一智能指针,他的替代方案时shared_ptr,它能够持续的跟踪共有多少个对象指向资源,在无人指向资源时才删除该资源,但是由于shared_ptr在析构函数中使用的是delete而不是delete[],对于动态分配的数组显然不可取,针对动态数组的智能指针在c++11中并没有提供,但在幸运的事boost中有我们想要的boost::scoped_array和boost::shared_array,google c++ sytle中建议需要使用智能指针的话尽量使用scoped_ptr,只在非常特定的情况下使用 std::tr1::shared_ptr, 例如 STL 容器中的对象。“智能” 指针看上去是指针, 其实是附加了语义的对象. 以 scoped_ptr 为例, scoped_ptr 被销毁时, 它会删除所指向的对象. shared_ptr 也是如此, 并且 shared_ptr 实现了引用计数, 所以最后一个 shared_ptr 对象析构时, 如果检测到引用次数为 0,就会销毁所指向的对象。一般来说,我们倾向于设计对象隶属明确的代码, 最明确的对象隶属是根本不使用指针, 直接将对象作为一个作用域或局部变量使用. 另一种极端做法是, 引用计数指针不属于任何对象. 这种方法的问题是容易导致循环引用, 或者导致某个对象无法删除的诡异状态, 而且在每一次拷贝或赋值时连原子操作都会很慢。

    假如将shared_ptr用在互斥器中(mutex objects)

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

    shared_ptr缺省时将引用次数为0时删除所指物,然而在Mutex中,我们要做的释放动作时解锁而不是删除,这就要用到shared_ptr中的删除器来指定代替默认状态下的删除操作,本例中引用计数为0时则自动调用unlock函数

    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 Item15 for info on “get”
      }
    private:
      std::tr1::shared_ptr<Mutex> mutexPtr; // use shared_ptr
    };

    new与智能指针

    假设我们有一个函数来解释处理程序的优先权,另一个函数用来动态分配Widge上进行某些优先权处理:

    int priority();
    void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);

    processWidge决定动态分配得来的Widge运用智能指针

    processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority());

    虽然这里使用了智能指针,但还是会有泄露的发生。

    实际参数("std::tr1::shared_ptr<Widget>(new Widget)"),由两部分组成:new Widge表达式和shared_ptr构造函数,但是c++编译器的运行次序可不是按照参数次序来执行,对于priority的调用可能会在new Widge表达式和shared_ptr构造函数两个操作的之前,中间,最后执行,问题在于如果非常不巧的priority在第一个实参的两个操作之间执行,又非常不幸priority调用时抛出异常:

    1. Execute “new Widget”.
    2. Call priority.
    3. Call the tr1::shared_ptr constructor.

     第一个new操作的建立 的资源将没有办法回收。

    避免这一问题的办法是分离语句,明确调用顺序

    std::tr1::shared_ptr<Widget> pw(new Widget); // store newed object
    // in a smart pointer in a
    // standalone statement
    processWidget(pw, priority()); // this call won’t leak

     

  • 相关阅读:
    canvas之碎碎念
    canvas之动态时钟
    属性小问题
    readonly and disabled
    table
    地图热区
    子块元素在父块元素中居中
    Ajax与JS
    前端测试
    html5/css3
  • 原文地址:https://www.cnblogs.com/loujiayu/p/3602723.html
Copyright © 2020-2023  润新知