Effective C++

2017-12-24  本文已影响0人  卡卡西sisi

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时

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来表示其代表一个类型
}
上一篇 下一篇

猜你喜欢

热点阅读