美文网首页
Effective C++

Effective C++

作者: 卡卡西sisi | 来源:发表于2017-12-24 20:06 被阅读0次

    1, C++.federation.png

    2, const + enum kill #define

      functions: inline kill #define

    3 use const whenever possible

       const char *p = "hello" const data, non-const pointer
       char * const p = "hello" non-const data, const pointer

    4, default member function

    class Empty
    {
      public:
        Empty(){}          //构造
        Empty(const Empty& rhs){}    //拷贝构造
        Empty(const Empty&& rval){}    //移动构造
        Empty& operator=(const Empty& rhs){}   //赋值
        Empty& operator=(const Empty&& rval){}    //移动赋值
        ~Empty(){} 
    };
    

    5 c++ 不允许reference指向其他对象

        int a = 1,b=2
        int &ra = a,&rb = b;
        ra = b;   //此处是assignment, 此时已经修改了a的值,但是ra依旧是a的reference
    

    7 不想或不允许使用default member function时

    • 声明为private, 不去实现或定义
    • 使用Uncopyable这样的base class

    8 不要让exceptions逃出destructor

    程序出现exceptions时,系统会自动调用相应的destructor,此时如果有多个object的destructor被调用,
    意味着有多个exceptions同时出现,然后系统就蒙了
    

    9 对于多态的base class,最好将其destructor声明为virtual

    why not constructor be virtual?
    1, 虚函数实行run-time binding, 在constructor之前,无法确定the type of the object, so, 无法调用虚函数
    

    10 not call "virtual function" in "constructor" and "destructor"

    //.h
    class Base
    {
      Base()
      {
        vfun();
      }
      virtual vfun();  
    };
    
    class Derive:public Base
    {
      Derive()
      {
        vfun();
      }
    virtual vfun();
    }
    //.cpp
    Derive d;  //此时,base class的constructor先于derive class的constructor,当base class完成构造时,由于derive尚未构造,此时会调用base class的虚函数,违背了虚函数与实际对象一致的规则
    
    

    11 operator= 返回reference to *this

    假设返回对象本身,a=b=c,首先执行b=c,返回一个临时的对象temp(需要用到构造函数),然后再执行a=temp,增加了拷贝代价
    当然该协议也适用于operator +=, -=,*=, /=
    

    12 operator= 处理自我赋值

    1, 添加 identity test(不能保证异常处理)
    
    2, exception safe.JPG

    13 如果自己写copy constructor,确保copy所有的local variable and all the variable in the base class, 否则编译器不会再提醒你

    another advice: 不要在copy constructor 与copy assignment之间互相调用,因为语义不符
    前者是构造对象,后者是已经完成对象初始/构造 化的重新assignment
    

    13 RAII(resource acquisition is initialization), 使用对象管理资源,主要是shared_ptr<>

    shared_ptr<int> ptr = new int;
    attention, 对于shared_ptr <int> p(new int[10]), 析构时也无法完成,因为调用的是delete, not delete[], to solve this, 使用vector/string 代替array.
    

    14 copy RAII对象时记得copy他对应的resource

    15 RAII对象中需要对原始资源进行访问时,可以显示调用(更加安全),隐士调用(方便但可能不安全)

    17 独立语句完成RAII对象

    int fun1()   //a function
    fun((shared_ptr<T>) new T, fun1()) //此时编译器会对同一行的语句进行优化,意味着2B编译器会出现以下顺序:
    1 new T
    2 fun1()
    3 shared_ptr<T> = p;// p = new T
    如果在2中throw exception, 意味着new了一块东西,却没办法释放
    

    20 pass-by-reference-to-const 代替pass-by-value

    1, 更高的效率  //注意一般为const,不然很容易修改对应值
    2,避免slicing problem,其实就是参数为base class, 传进来的却是derived class
    3, 对于短小精悍的内置类型和函数对象还是pass-by-value
    
    

    24 所有参数需要类型转换时,采用non-member

    class Rational
    {
    public:
      Rational(int a=0,int b=0);
      const Rational operator*(const Rational& rhs)
      {...}
      int a, b;
    };
    Rational ration(1,2);
    Rational m = ration * 2; //correct  equal: m = ration.operator*(2);
    Rational m1 = 2 * ration; //wrong!   equal: m1 = 2.operator*(ration)
    why? 当变量位于参数列表中时才会发生隐士转换。第一个,调用operatpr*后需参数为Rational, 发生Rational tem = 2;第二个,2不是一个class,无法调用operator,即2无法置身于一个参数列表中
    

    26 尽可能延后变量出现的时间,尽可能出现即初始化(效率)

    27 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全; const_cast 唯一可以去掉const的修饰

    static_cast vs dynamic_cast

    28 避免返回handles(包括reference,pointer,iterator)指向对象内部,因为对象可能会析构,只留下一个dangling handle.

    异常安全的函数特点:
    1, leak no resource
    2, don't allow data structure to be corrupted
    

    32 public 继承,表示“is_a”, 适用于base class的每一种操作也适用与derived class ;

    33 derived class 会遮掩 base class的名称,而在public继承下希望去除遮掩,可以using 或 forward functions.

    class Base
    {
      void f1();
      void f1(int);
      virtual void f2();
    };
    class Derived: public Base
    {
      void f1();
      virtual void f2();
    };
    Derived d;
    d.f1();  //correct, call derived f1();
    d.f1(2);  // no function in derived class; 
    

    34 public继承中,derived class 总是继承base class的所有接口

    pure virtual : 只具体制定接口继承
    virtual : 指定接口继承同时指定了缺省的实现
    non-virtual : 指定接口继承以及强制性实现继承
    

    37 不重新定义继承而来的缺省参数值

    c++为了效率,对缺省参数静态绑定
    

    38 is_a    has_a    is_implemented_in_terms_of

    is_a : public inheritance, 所有适用于base class的操作都适用于derived class
    has_a: in application domain, composition means "has_a", in implementation domain, composition means "is-implemented-in-terms-of". 
    

    42 申明template时,class 与typename 等价;但typename可以表示嵌套从属类型

    template<class T>
    void fun(T& C)
    {
      C::const_iterator ite;  //此时编译器无法确定C::const_iterator是一个类型还是一个变量,统一认为不是一个类型,前面加上typename来表示其代表一个类型
    }
    

    相关文章

      网友评论

          本文标题:Effective C++

          本文链接:https://www.haomeiwen.com/subject/bobrwxtx.html