zoukankan      html  css  js  c++  java
  • 读书笔记五

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


    • 尽量少做转型动作
      •   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。


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

  • 相关阅读:
    [转]使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(三)-- Logger
    [转]ASP.NET Core配置环境变量和启动设置
    [转]ASP.NET Core 指定环境发布(hosting environment)
    [转]COPY OR MOVE FILES AND FOLDERS USING OLE AUTOMATION
    [转]How to Use xp_dirtree to List All Files in a Folder
    [转]How to nest transactions nicely
    [转]Using TRY...CATCH in Transact-SQL
    [转][C#] 对List<T>取交集、连集及差集
    [转]Pass a ViewBag instance to a HiddenFor field in Razor
    Apache Ignite简介以及Ignite和Coherence、Gemfire、Redis等的比较
  • 原文地址:https://www.cnblogs.com/Kobe10/p/5741944.html
Copyright © 2011-2022 走看看