读书笔记五

  • 尽可能的延后变量定义式出现的时间
    •   产生问题:定义一个变量,其含有构造函数和析构函数。那么当代码运行到它的时候,就必须会产生构造成本和析构成本,如果这个变量最终未使用,那么就是浪费了资源空间,所以应该尽可能的延后变量定义式的时间
    •   解决方法:不只是应该延后变量的定义,知道非得使用该变量的前一刻为止,甚至应该尝试延后这份定义知道能够给他初值实参为止。这样可以避免构造析构函数和默认构造函数
    •   对于循环体中的变量:一般定义在循环体外部所需要的开销要少的多,不是定义在循环体中的局部变量   


  • 尽量少做转型动作
    •   C++的四种转型手法:http://www.cnblogs.com/jerry19880126/archive/2012/08/14/2638192.html
    •   如果可以尽量避免转型特别是在注重效率的代码中避免dynamic_casts,如果有个动作需要转型,试着写一个无需转型的动作代替
    •   如果非得转型,试着将它藏在某个函数之后,客户可以随后调整该函数,而不是必须的将它放在代码中
    •   宁可使用新型的转型方式也不要去使用旧的转型方式


  • 避免返回handles指向对象内部成分
    •   问题产生:
      class point{
          point(int x,int y);
          ...
          void setx(int newval);
          void sety(int newval);
      };
      struct rectdata{
          point u;
          point l;
      };
      class rectangle{
      public:
          point & upperleft()const{return pdata->u;}
          point & upperright()const{return pdata->l;}
      private:
          std::str1::shared_ptr<rectdata> pdata;
      };
      int main()
      {
          point coord1(0,0);
          point coord2(100,100);
          const rectangle rec(coord1,coord2);
          rec.upperleft().sety(50);
      }
      这里我们能够通过最后的这个函数去修改private成员的值,那么私有成员变量就不是私有的了而是public的。
      最根本的原因是由于upperleft函数返回的是一个reference 指向rectangle对象的,所以私有变量就不是私有的了,失去了安全性和封装性
      View Code
    •   reference,指针,迭代器都是handles中的一类,都是用来取得某个对象的一种工具,而返回代表一个内部对象的handles,他们很有可能修改成员变量和const成员函数,降低了类的封装性
      •   解决方法:让函数加上const,这样就不能修改值,只能读取值了。
        const point & upperleft()const{return pdata->u;}
            const point & upperright()const{return pdata->l;}

         但是这又会产生一个新的问题,就是point&返回的对象可能发生它所指的东西不存在了。这个例子感觉比价深啊。详见书P126

    •   避免返回handles(包括reference,指针,迭代器)指向对象内部。可以增加封装性,帮助const成员函数的行为像个const,并发生虚掉号码牌的可能性降至最低。


  • 为异常安全努力是值得的
    •   问题的产生
      class prettymenu{
      public:
          void changebackground(std::instream & imgsrc);
      private:
          Mutex mutex;
          Image *bgimage;
          int imagechanges;
      };
      void prettymenu::changebackground(std::istream&imgsrc){
          lock(&mutex);
          delete bgimage;
          ++imagechanges;
          bgimage=new image(imgsrc);//这个异常会导致unlock无法调用,资源泄漏;new异常原互斥器没有解锁,然而imagechanges还是++了,但是并没有一个新的image产生,数据被破坏了
          unlock(&mutex);
      }
      //这个例子没有遵守异常安全的两个条件
      //①不泄露任何的资源,②不允许数据的破坏
      //unlock的资源泄漏问题可以很容易解决:利用lock class类就能解决,所以把最后一句删除即可。
    •   解决方法:
      •   异常安全提供三个保证:
        •   强烈保证:如果异常被抛出了,程序中的所有东西仍然保持有效状态,任何数据结构或者对象会被破坏,抛出异常前后并没有发生变化。
        •   基本保证:异常抛出,程序状态不改变。函数成功,就是完全成功,函数失败,程序回复到调用函数之前的状态。
        •   承诺绝不抛出异常,总是能够完成要承诺完成的事情。
      •   一般而言,只能够做到第一条和第二条。一个好的操作方法是:pimpl idiom方法:copy and swap,将所有隶属对象的数据从原对象放进另一个对象内,然后赋予原对象一个指针,指向那个所谓的实现对象(副本)。实现所有操作后在进行swap,这个提供的是强烈保证
        struct PMImpl{
            std::tr1::shared_ptr<image> bgimage;
            int imagechanges;
        };
        class prettymenu{
        public:
            void changebackground(std::instream & imgsrc);
        private:
            Mutex mutex;
            std::tr1::shared_ptr<PMImpl> pimpl;//防止内存泄漏
        };
        void prettymenu::changebackground(std::istream&imgsrc){
            lock m1(&mutex);//获得mutex的副本数据
            str::tr1::shared_ptr<PMImpl> pnew(new PMImpl(*pimpl));//
            pnew->bgimage.reset(new image(imgsrc));//修改副本
            ++pnew->imagechanges;
            
            swap(pimpl,pnew);//置换数据,释放mutex
        }
      •   让函数具备异常安全性的方法步骤:①以对象管理资源:防止内存泄漏。②挑选三个异常安全保证中的一个实施与函数中,保证异常安全性,选择上应该选择第二个。


  • 透彻了解inlining的里里外外(内联函数)
    •   inline函数的表示
      •   隐式的:声明在类体内部,有些friend也可以是inline函数
        class person{
        public:
            int age()const{return theage;}
        private:
            int theage;
        };
      •   显示的,在函数前面加上inline关键字

    •   inline函数通常都是置于头文件中的,在编译过程中进行inlining,必须知道函数本体长什么样子,才能将函数所有本体代码替换执行的inline函数。所以inlining一般都是编译期的行为。
    •   由于inline是在编译期执行的,而虚函数时在运行的时候才将该函数具体化执行的。所以凡是虚函数一般都不是inline函数。所以,一个表面上看起来inline'的函数是否真的inline,取决于环境,主要屈居于编译器。如果无法inline,会发出一个警告信息。
    •   class类中的构造函数和析构函数一般是不能使用inline的,因为成本开销可能非常的大,但是表面上看不到它的开销,所以不适合使用。
    •   将大多数inlining限制在小型的,频繁调用的函数上。不要只因为function出现在头文件,就将他们声明为inline。


  • 将文件间的编译依存关系降至最低
    •   

原文地址:https://www.cnblogs.com/Kobe10/p/5741944.html