【Effective c++ 】总结笔记(一)

条款03 const

  1. const 与作用域:
    1. global作用域中的常量
    2. local作用域中的static对象
    3. class内部的static或nonstatic成员变量
  2. const 修饰指针或指针所指的对象:    const 类型 * const 指针名
  3. const 修饰迭代器: 迭代器类似一个指针 T*
    1. const 的 iterator : 类似 T* const 指针名 ,const 修饰的是迭代器这个指针,即 迭代器不可变,但迭代器所指的对象可以改变
    2. const_iterator: 类似 const T* 指针名,const修饰的是迭代器所指的对象,迭代器可变,但迭代器所指的对象不可变
  4. const 与 函数声明
    1. const 修饰返回值:具有安全性和高效性,提高容错率。比如为了防止 (a*b)=c 这个语句出现,我们在operator* 成员函数的返回值char& 前加上const,使得返回值不可被改变,即不能被赋值,即不能出现在赋值号左边。                              (为何在返回类型后加引用&  ?  因为如果返回的是内置类型(非引用),改变她的值是不合法的。纵使合法,通过by-value传递的对象,是我们期望传递的那个对象的一个副本,并非对象其本身)
    2. const 修饰参数:参考 条款20 尽量以pass-by-reference-to-const 替换 pass-by-value
    3. const 修饰成员函数:
      1. 重要性:
        1. 使class的接口更明显,即容易得知哪个成员函数能够改变成员变量,哪个不可以
        2. 操作const成员对象:我们可以通过pass-by-reference-to-const传递const对象,从而提高程序效率,cosnt成员函数可以操作传递而来的const对象
      2. 两个constness
        1. bitwise constness 认为const成员函数不可以改变任何non-static成员变量(漏网之鱼:如果成员变量是指针呢?使用const成员函数操作const指针,指针值确实不变,但是指针所指的值却可以改变,不符合const成员函数的意义)
        2. logical constness 认为const成员函数可以改变成员变量的某些bit,但是不能被编译器发现。所谓做人留一线,日后好相见。就是不要在成员函数中公然赋值给成员变量,这就过分了,编译器不会让你通过的。
        3. 如果希望在const成员函数中操作non-const成员变量?将non-const成员变量使用mutable修饰
      3. const与non-const成员函数的重载
        1. 两个是不同的函数,支持重载,但为了避免重复代码过多,一般使用non-const成员函数调用const成员函数,当然在调用之前使用static_cast将类型转换为const T&,调用完之后使用const_cast消除const T&的常量性

条款04 使用对象前确保初始化

  1. class内的初始化:
    1. 尽量使用member initialization list初始化:成员变量是 内置类型 const 或者 reference (先初始化menber initialization list内的成员变量或不在list内但是有default constructor 的成员变量,再执行构造函数本体的语句)(使用member initialization list初始化是直接调用copy构造函数,而在构造函数本体内赋值是先用default构造函数初始化,而后使用copy assignment运算符,可以明显看到显然用member initialization list效率高一些)
    2. 初始化次序:(总结自 《探索c++对象模型》
      1. 首先判断如果有virtual base class,有多个则按照从左到右,从深到浅的次序初始化
        1. 使用member initialization list 初始化virtual base class,如果有参数需要传递则必须传递
        2. 不在list中,但virtual base class有default constructor,则使用default constructor初始化
        3. class中每一个virtual base class subobject 的偏移量offset,必须在执行期可被存取
      2. 然后判断如果有nonvirtual base class,有多个则按照base class的声明次序初始化
        1. 使用member initialization list 初始化base class,如果有参数需要传递则必须传递
        2. 不在list中,但base class有default constructor,则使用default constructor初始化
        3. 当初始化第二个及后继的base class时,this指针需要调整
      3. 初始化每一个vptr,将其指向适当的virtual function table
      4. 初始化member成员变量,有多个则按照member声明次序初始
        1. 使用member initialization list 初始化member,与list的顺序无关,还是按照member声明次序初始化
        2. 不在list中,但member有default constructor,则使用default constructor初始化
  2. static对象的初始化次序
    1. non-static: stack和heap-based
    2. static:
      1. local static:函数内声明为static的对象
      2. non-local static: 在global范围内,在namespace作用域内,在class内,在file文件内的static对象(不同编译单元内定义的non-local static对象初始化次序不明确,很可能会出现调用未初始化的static对象的操作。为了防止这种操作,我们可以将non-local static对象转为local static对象。具体是在一个专属函数中声明该static对象,然后该函数返回一个该static对象的引用,当我们需要使用该static对象时直接调用该函数。由于local static的初始化次序是有明确定义的,即”在函数调用期间“”并且首次遇上static对象的定义“时初始化,当我们调用该专属函数并得到static对象的引用时,可确保该static对象是已被初始化的。)

条款05 06 10 11 copy assignment

  1. 当成员变量有const 或者 reference时,想要支持赋值操作,必须自己定义copy assignment
  2. 想要class不支持赋值操作,也为了防止编译器自己合成一个copy assignment ,可以将copy assignment设置为private
  3. operator = 函数
    1. 返回值是reference-to-*this ,即return *this
    2. 防止自我赋值,可在函数头加上 判断语句 if(this==&rhs)
    3. 注意语句顺序:最好在分配好一个完整的新内存之后,再删除旧指针所指的对象
    4. 使用swap-and-copy技术
      1. 对于参数const T& rhs,创建一个rhs的副本temp,并swap *this和temp的数据,最后*this的数据是rhs中的数据(副本),temp中的数据是旧数据,再return *this之前自动销毁。
      2. 技巧:可以使用by-value传实参,因为by-value方式会产生T rhs的一个副本,与上条的temp的作用相同。

条款07 在多态基类中声明virtual析构函数

  1. 对于一种情况: Base* name = new Derived() 即一个base class 指针指向一个derived class 对象,当我们delete name删除该指针所指对象时:
    1. 如果Base类的析构函数是non-virtual,即不支持多态,那么只删除了base class部分,derived class成分未删除,即造成了局部删除的困境
    2. 如果Base类的析构函数是virtual,即支持多态(《探索c++对象模型》多态的主要用途:多态是经由共同接口来影响类型的封装,这个接口通常定义在base class抽象类里,接口由virtual机制引发,直到执行期时才能知道对象的真正类型(这个例子是Derived class类),并执行哪个函数实体(这个例子是Derived class 的 virtual 析构函数实体)) ,说明她会删除整个对象,包括derived class成分。
  2. pure virtual 析构函数的应用:如果你希望一个base class是抽象类,但是这个类中没有其他可用的virtual函数了,你可以设置base class 的析构函数为pure virtual destructor
    1. 抽象类一般为base class,即我们声明的这个类是基类,她会派生其他类,参考上条我们可以将这个base class的析构函数声明为virtual
    2. pure 可提供抽象类,即声明了pure之后这个class 无实体
    3. 值得注意的一点:如果你在base class 声明了pure virtual 析构函数,我们必须定义这个析构函数,如Base::~Base(){}(因为析构函数的运作方式是:在derived class的析构函数中静态调用base class 的析构函数,如果我们没有提供那个定义那么链接会断,编译器会出错的)

条款08 不要在构造函数和析构函数中调用virtual函数

  1. 在base class构造和析构函数中调用的virtual函数不可下降至derived class阶层,即base class 调用的virtual函数是base class版本的virtual函数实体,derived class 调用的virtual函数是derived class 版本的virtual函数实体。
  2. 纵使base class构造和析构函数中调用的virtual函数可以下降至derived class阶层,在执行derived class构造函数初始化derived成员变量之前,会首先执行base class的构造函数,这个构造函数调用的virtual函数如果是derived class版本的函数实体,由于derived class的virtual函数几乎必须调用其成员变量(此时还未被初始化),所以base class 的构造函数会调用到derived class 还未初始化的成员变量,这样非常不安全。
  3. 如果base class构造和析构函数必须使用derived class中的信息,可以将之前调用的virtual变成non-virtual,并且在derived class初始化成员队列里面将base class构造函数所需的信息当作参数传递进去,既可以实现将derived class中的信息上升至base class阶层。如果要传递的信息是derived class 还未被初始化的成员变量,可参照条款04,将这个成员变量封装在static专属函数中,她无需derived class对象构建完成,就可以先初始化,然后被我们使用。

条款13 auto_ptr和shared_ptr

  1. auto_ptr 智慧指针
    1. 当控制流离开作用域之时,auto_ptr自动调用delete删除所指的对象
    2. 两个auto_ptr不能指向同一个对象,如果两个指针销毁的话会delete两次对象,因为这个原因,auto_ptr的copy构造函数和赋值操作都具有破坏性和异常,对于 两个auto_ptr对象 ap1 = ap2,会删除ap1中的对象,然后将ap2中的对象赋值给ap1,ap2指向null。
  2. shared_ptr 引用计数型智慧指针(RCSP)
    1. std::trl::stared_ptr
    2. copy构造函数和赋值函数都正常

条款20 尽量以pass-by-reference-to-const 替换 pass-by-value

  1. 以pass-by-value方式传递对象至函数,会调用copy构造函数以实参值初始化一个复件,在函数返回前调用析构函数删除这个复件,调用端返回值获得的函数返回值也是一个复件。所以by-value方式会调用多个copy构造函数和析构函数。
  2. by-reference-to-const方式传递的好处?
    1. 可以避免对象分割(slicing)问题。当一个derived class对象以by-value方式传递至函数,并视为一个base class对象时,会调用base class的copy构造函数,则derived class成分会被切割掉,只留下一个base class对象。而如果使用pass-by-reference方式传递,则会调用真实类型(即derived class类型)的copy构造函数,避免对象分割问题。
    2. 不会有任何copy构造函数和析构函数被调用。
    3. 声明const可以保证函数内不改变传入的实参。对于by-value方式来说,为了保护传入的实参,函数内部不会对传入的参数做任何改变,只会对传入参数的一个副本做改变。对于by-reference方式来说,声明一个const,可以保证传入的实参不做改变。

条款27 转型

  1. const_cast 常量性消除
  2. dynamic_cast 安全向下转型
  3. reinterpret_cast 低级转型
  4. static_cast 强迫隐式转型

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值