• 读书笔记三


    • 以对象管理资源
      •   问题产生:当一个类的一个函数返回的是一个指针,指向这个类的对象。然后有这么个函数
        void f(){
        my * p=createmy();返回对象的指针    
        ...
        delete  p;
        }

         因为...这个东西可能不能够删除那个指针,资源就没有办法释放了。..可能发生过早的return语句,或者delete处于循环之中,这些都不能让资源正确安全的释放。

      •   解决方法:把资源放进对象内,依赖C++的析构函数自动调用机制确保资源被释放,然后利用auto_ptr的特性。auto_ptr详见http://www.cnblogs.com/Kobe10/p/5737305.html
        void f(){
        std::auto_ptr<my> p(createmy());   //这里初始化为my类型对象的指针  ,指向的是createmy函数创建的对象
        //调用工厂函数 ... }

         获得资源后立即放进管理对象中,my返回的资源被当做其管理者auto_ptr的初值。资源取得的时候便是初始化时机。
        管理对象运用析构函数确保资源被释放。一旦对象被销毁,析构函数自动的调用,资源被释放。

      •   由于auto_ptr的一些特殊的性质:比如一旦复制,之前的对象就失去了它的所属权,所以我们用RCSPs(share_ptrs),他也是个智能指针,但是它的功能更强大,能够持续追踪共有多少对象指向某笔资源,并在无人指向它的手自动删除该资源。
      •   为了防止资源泄漏,请使用RAII对象,他们在构造函数中获得资源并在析构函数中释放资源
      •   两个常常被使用的RAIIclasses分别是tr1::shared_ptr,auto_ptr,前者较好。

    • 在资源类中小心coping行为
      •   问题产生:当一个RAII对象被复制的时候,会发生什么事情。
      •   解决问题:
        •   禁止复制:有时候复制行为并不是合理的,我们需要禁止它。我们可以调用条款6的一个机制:将copiny操作声明为private。详见:http://www.cnblogs.com/Kobe10/p/5736036.html
          class my :private uncopyable{
          public:
          ...}
        •   使用引用计数法(也就是shared_ptr指针):保存资源,每次复制的时候都递增一个引用数,shared_ptr指针的内容也多了一个。该指针容易实现reference-counting coping行为,但是这个是一个引用类型的资源,当引用次数为0的时候,不是将其删除而是将其锁定,所以我们这里需要这样写,当引用次数为0的时候,调用shared_ptr中的所谓的删除器,可以实现锁定任务,删除器就类似一个函数,把最后我们的析构函数中的内容放进这个函数再传递给构造函数中的参数:
          class lock{
          public:
              explicit lock(mutex * pm)
                  :mutexptr(pm,unlock)//这里unlock就是那个所谓的删除器,析构函数中的内容,也可以相当于一个delete功能的函数
            实际上tr1::shared_ptr的构造函数可以接受两个参数,一个是被管理的指针,另一个是引用次数变成0之后时将调用的删除器  
          {lock(mutexptr.get();} private: std::tr1:;shared_ptr<mutex> mutexptr; };
      •   复制资源管理对象必须一并复制它所管理的资源,所以资源的coping行为决定资源管理对象的coping行为


    • 在资源管理类中提供对原始资源的访问
      •   APIs往往要求访问原始资源,所以每一个RAII class应该提供一个‘取得其所管理之资源’的方法,例如shared_ptr的get方法,可以指向类的原始参数。
      •   对原始资源的访问可能经由显示转换或者隐式转换。一般而言显示转换比较安全,单隐式转换对客户比较方便。


    • 成对的使用new和delete时要采取相同的形式
      • string *ptr1-new std::string;
            string *ptr2=new std::string[100];
        
            delete ptr1;//删除一个对象
            delete []ptr2;//删除一个由对象组成的数组
        
            typedef string arrline[4];//这里定义了一个arrline是一个string*对象,因为他是一个string数组
            string * p1=new arrline;//这里new的时候   p1是一个string*对象,所以delelte应该是delete[]
        
            delete []p1;


    • 以独立的语句将newed对象置入智能指针中
      •   问题产生:
        • int priority();
              void precessWidget(tr1::shared_ptr<Widget> pw,int priority);
              processWidget(tr1::shared_ptr<Widget>(new Widget),priority());//调用上述函数

           当调用上述函数的时候,在函数体内参数的执行顺序可能使不同的。要执行三个操作:调用priority,执行new  widget,调用tr1::shared_ptr构造函数。当priority调用的顺序处在另外两个中间的时候,这个时候它自己发生异常,导致new的东西进不到智能指针中,就会发生内存泄漏了。

      •   解决办法:
            tr1::shared_ptr<Widget> p1(new Widget);在单独的语句中以智能指针存储new的对象
            processWidget(p1,priority())
      •   以独立的语句将newed对象存储于智能指针中。不这样可能会发生异常泄漏


  • 相关阅读:
    C#’s ~ vs Java’s finalize
    做Java开发这一年
    assertThat, assertEquals, assertTrue
    给Cuke4Duke添加一个AfterAll标签(一):使用Cuke4Duke
    心理问题的根源
    何谓数学
    人生谁看透
    人本主义与自由意志
    哲学的基本问题
    贫穷与教育
  • 原文地址:https://www.cnblogs.com/Kobe10/p/5737478.html
Copyright © 2020-2023  润新知