more effective c++使用条款(一)—— 基础议题/运算符

来源:互联网 发布:北京办公软件速成班 编辑:程序博客网 时间:2024/06/18 06:05

第一章:基础议题
  Item M1:指针与引用的区别
    1.指针可以不初始化,引用必须初始化
    2.指针可以为空指针,引用不可以为空
    3.指针可以改变指向,引用初始化后就不能改变指向的对象
    4.指针占用4个字节,引用只是别名,理论上是不占用空间的,但是这个别名本身是要占用空间的,因此也可以说引用时占用空间的
    5.引用比指针效率高,因为引用直接操作的是原对象本身
  Item M2:尽量使用C++风格的类型转换
    1.C++风格的四种转换:static_cast ,const_cast,dynamic_cast,reinterpret_casts
    2.static_cast与C语言的强制类型转换类似
    3.const_cast用于去除变量的常属性
    4.dynamic_cast用于从基类引用(指针)动态转换为子类引用(指针),当转换失败时返回NULL或抛出异常(不能用于缺乏虚函数的类型上)
    5.reinterpret_cast一般用于函数指针之间的转换,但是不到万不得已不使用
  Item M3:不要对数组使用多态
    1.在多态中,不要将子类对象的数组转换为基类对象的数组,这样会丢失子类的信息,且导致数组访问时由于基类和子类的大小不一样导致未定义的行为。
     数组作为参数传递时,arr[i]的本质是*(arr + i),由于基类和子类对象所占用内存大小不一样,导致出错)
    2.如果需要传递不同类型的数组,可以使用模板函数代替继承
  Item M4:避免无用的缺省构造函数
    1.缺省构造函数作用:可以通过无参调用构造函数构建对象,比如classA *parr = new  classA[10];此时就是调用的classA的无参构造函数,如果没有无参构造函数则创建数组时会出错
    2.对于类里没有定义缺省构造函数所造成的第二个问题是它们无法在许多基于模板 (template-based)的容器类里使用 。因为实例化一个模板时,模板的类型参数应该提供一个缺省构造函数,这是一个常见的要求。
    3.提供无意义的缺省构造函数也会影响类的工作效率,如果要提供缺省构造函数,则应该保证该类被完全正确的构造
 
第二章:运算符
  Item M5:谨慎定义类型转换函数
    1.有两种函数允许编译器进行隐式类型转换:单参数构造函数和隐式类型转换运算符
    2.单参数构造函数是指只用一个参数即可以调用的构造函数,在需要的时候编译器可以隐式的将构造函数参数类型转换为一个该类的匿名对象。为了避免不必要的隐式类型转换,定义构造函数时使用explicit关键字
    3.隐式类型转换运算符:operator 关键字(此关键字就是需要转换的类型,如operator double() const; ),为了避免不必要的隐式类型转换,可以定义一个相同含义的函数取代隐式类型转换运算符
    4.为了避免隐式类型转换,可以定义operator操作符,比如:
  Item M6:自增(increment)、自减(decrement)操作符前缀形式与后缀形式的区别
    1.前缀和后缀的区别:后缀形式有一个 int 类型参数,当函数被调用时,编译器传递一个 0 做为 int 参数的值给该函数
    2.前缀形式返回一个引用,后缀形式返回一个 const 类型
    3.前缀效率高,后缀需要构造一个临时变量进行返回
  Item M7:不要重载“&&”,“||”, 或“,”
    1.“&&”,“||”具有短路效应,不应该重载他们——一旦确定了布尔表达式的真假值,即使还有部分表达式没有被测试,布尔表达式也停止运算
    2.“,”先运算左边,在运算右边表达式,并返回右边表达式的值
  Item M8:理解各种不同含义的new和delete
    1.new操作符(new operator)和new操作(operator new):new操作符做两件事:调用new操作分配内存,并调用构造函数初始化相关内存,这两点是语言特性,和sizeof一样是不可改变的。new操作时用户自定义的内存分配函数。
    2.自定义的operator new:void * operator new(size_t size); 返回值类型是 void*,因为这个函数返回一个未经处理(raw)的指针,未初始化的内寸。参数 size_t 确定分配多少内存。 你能增加额外的参数重载函数 operator new,但是第一个参数类型必须是 size_t。
第三章:异常
  Item M9:使用析构函数防止资源泄漏
    1.对于成员变量的指针,尽量在析构函数的时候进行delete(delete空指针是合法的)
    2.如果不在析构函数中释放内存,局部变量的指针即使显示的调用了delete,也可能由于异常导致内存泄露
    3.可以使用智能指针代替在析构函数中释放内存
  Item M10:在构造函数中防止资源泄漏
    1.如果在构造函数中分配了内存,但是构造函数还没完成时发生了异常,将导致内存泄露——C++的析构函数只能删除完全构造的对象
    2.避免构造函数中异常导致的内存泄露,常用的方法是捕获所有异常,然后清除内存,最后再重新抛出异常它继续转递
  Item M11:禁止异常信息(exceptions)传递到析构函数外
    1.在有两种情况下会调用析构函数。第一种是在正常情况下删除一个对象,例如对象超出了作用域或被显式地 delete。第二种是异常传递的堆栈辗转开解(stack-unwinding)过程中,由异常处理系统删除一个对象。
    2.如果在一个异常被激活的同时,析构函数也抛出异常,并导致程序控制权转移到析构函数外(使用try…catch(…),并且catch内部尽量少做事),C++将调用 terminate 函数 ,程序将立即终止,不会做任何处理
    3.如果一个异常被析构函数抛出而没有在函数内部捕获住,那么析构函数就不会完全运行
  Item M13:通过引用(reference)捕获异常
    1.通知指针传递异常时可能存在指针所指向的对象已经析构,导致非法内存访问
    2.通过变量传递异常时,子类信息会被丢失掉,完全转换为基类对象,它没有子类的数据成员,而且当准备调用虚函数时,系统调用的却是基类对象的函数
  

0 0
原创粉丝点击