Effective & More Effective C++总结

 一、说明。

1、E指的是《Effective C++ 第二版》

2、M指的是《More Effective C++ 第二版》

二、总结

1、如果需要定制自己的operator new(通常是在需要分配大量的小对象,而且对性能要求特别敏感的程序里),具体的使用准则请参看 E7/E8/E9/E10。

     (1)、全局的operator new 在<new>里定义,可以通过::operator new()调用。它的伪代如下

      

               它将循环执行内存分配,跳出循环的唯一办法是内存分配成功或出错处理函数完成。

  •                得到了更多的可用内存;
  •                安装了一个新的new-handler(出错处理函数);使用set_new_handler()函数设置。默认情况下new_handler将为NULL,此时operator new将自动抛出std::bad_alloc异常。如果设置了一个new handler函数,但又分配足够的内存,或者不退出,或者不抛出异常,那operator new 将一直循环执行。
  •                卸除了new-handler;
  •                抛出了一个std::bad_alloc或其派生类型的异常;
  •                或者返回失败。

               默认情况下,new handler是NULL,operator new 将不会循环,而是抛出std::bad_alloc退出。如果你通过调用set_new_handler()函数设置了一个异常处理函数,在你的new handler函数里,你必须要遵循上面说的5个条件之一或者更多。不然operator new将一直循环的调用你的new handler函数。

 

2、为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符,或者如果你不需要此两个函数,那么就要把他们声明为private。

    具体的使用准则请参看 E11。

 

    因为默认的类里自动为你生成了这两个函数,而且是使用浅复制的形式。所以你将有可能遇到以下情况:

  •     内存泄漏(即分配的内存没有指针指向,而又还没有删除)
  •     多重删除

     当实现赋值操作符时,准则是:一定要返回*this的引用 E15/E16/E17

     否则会出现:

     (1)无法连续赋值(因为要保持与普通=号的职责)

     正确的标准写法是:

    

3、基类要有虚析构函数。E14

     (1)否则将会导致:

     指针指向的子类无法调用正确的析构函数(当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。)

      (2)一般的做法是:当不需要要实例化基类时,最好把析构函数声明为纯虚析构函数(当然析构函数要有实现)。

      (3)把非基类的析构函数声明为虚析构函数,会导致两种问题:第一是性能问题,因为有了虚拟函数表;第二是与其他语言之间的交互,此问题一般比较少遇到。

 

4、尽量使用初始化而不要在构造函数里赋值

     const和引用数据成员只能用初始化,不能被赋值

     性能上考虑,如果是赋值,那么将会有两次的赋值过程,一次是在类成员声明里,一次是在赋值里;而初始化只有一次。

 

5、参数的实质

    例子:int function(int a,string b,string& c,string*d);

             function(1,"b","c","d");

    (1)、首先生成一个临时的对象。

              对于第1个参数,是生成一个int a,然后把int值1赋值给a。所以改变a的值没有办法改变值1。

              对于第2个参数,把"b"的值通过构造函数构造一个对象b,所以改变b的值也没有办法改变值"b";

              对于第3个参数,生成一个string&对象,此引用的对象类似与指针,把"c"的地址传给string&对象,所以改变c的内容,将改变"c"的内容。但无法再次改变c的指向,因为c是一个引用。

              对于第4个参数,生成一个string*对象,任何对象的指针的大小在一般的系统下都是4个字节大小,然后把"d"的地址传递给d,

所以改变d的内容将改变"d"的内容。但如果把d再赋值另外的地址,因为已经指向了另外一个地址,d对象的内容的改变将无法影响"d"。

      结论:任何形式的参数传递都是值传递,但值的类型由参数的类型决定。或者是个对象,或者是个指针,或者是个引用。

 

 6、尽量使用const;尽量传引用,不传值;函数重载和默认缺省参数要仔细考虑;不要对指针和数字类型重载;

 

 7、类设计要点。

    (1)C++编译器自动生成缺省构造函数、拷贝构造函数、析构函数、赋值运算符、取址运算符。如果不想使用这些默认定义,应该重定义他们或者直接使用private屏蔽。

     定义一个类:

     class Empty{};

     等价于

    

    

    (2)operator= 的设计。E15/E16/E17

  •      检查给自己赋值的情况
  •      对所有数据成员赋值
  •      返回*this的引用

    

 

    (3)、公有继承、存虚函数、虚函数、非虚函数的意义

        纯虚函数意味着仅仅继承函数的接口。如果类C声明了一个纯虚函数mf,C的子类必须继承mf的接口,C的具体子类必须为之提供它们自己的实现。见E36。
       简单虚函数意味着继承函数的接口加上一个缺省实现。如果类C声明了一个简单(非纯)虚函数mf,C的子类必须继承mf的接口;如果需要的话,还可以继承一个缺省实现。见E36。
      非虚函数意味着继承函数的接口加上一个强制实现。如果类C声明了一个非虚函数mf,C的子类必须同时继承mf的接口和实现。实际上,mf定义了C的 "特殊性上的不变性"。见E36。

      决不要重新定义继承而来的非虚函数  E37

       虚函数的使用要特别注意,因为子类都默认继承了实现,所以虚函数的实现子类必须是要一致的。E36

  

 8、非局部静态对象初始化。E47.

      使用函数内定义的技巧保证初始化。

 

     

未完待续~~~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值