Effective c++学习笔记

条款5:c++默认编写构造,析构,copy构造,copy assignment函数

  • 对于copy构造,和copy assignment函数,c++默认情况下会自动编写。
  • 但是有些特殊情况下是不会自动声明copy assignment函数(这些情况copy构造依然自动声明),而是将其设置为=delete,此时必须显示编写自己copy assignment函数:
    1、成员变量中含有non-static reference成员(为什么类的引用成员在默认copy assignment中不能赋值?(成员指针不会发生这种情况)或者含有const 成员
    2、成员变量中含有non-static的不能使用copy assignment的成员。
    3、继承了不能使用copy assignment的基类。
  • 只有当调用析构函数、copy构造函数、copy assignment运算符时,编译器才生成它们,请大家分清楚,声明和生成是两码事。

条款6:不让编译器自动生成默认函数

  • 将自动生成的函数声明为private,而且只声明他们,而不定义他们(声明语句后面连花括号都不加)。或者继承一个将函数声明为private的基类。
  • 不过如果基类的copy构造和copy赋值函数不可用(参考上一条),那么他的派生类的copy构造和copy赋值函数也不会自动生成,因为派生类的会调用基类的copy构造和copy赋值函数。
  • 当然可以显示声明这些函数为=delete。

条款7:virtual析构函数

  • 当一个类作为多态性(基指针指向派生类对象)基类的时候,需要将其析构函数设置为virtual;否则,通常情况下不会设置为virtual(除非该类中有其他virtual函数)。一个类的某个函数设置为virtual是需要付出额外的代价的:类需要多存储一个指针vptr来指向由函数指针构成的数组vtbl。
  • 不要随意继承标准库的类,因为很多没有virtual函数,这样很容易造成内存泄漏。
  • 如果想将某个没有pure virtual函数的类声明为抽象类,那就将析构函数声明为pure virtual函数,并且定义这个析构函数

条款9:不要在构造和析构函数内使用virtual函数

  • 在基类构造或者析构函数内使用virtual函数,会导致virtual函数不会调用派生类的virtual函数。因为在创建派生类对象时,先调用基类构造函数构造基类对象,而此时编译器会认为该对象是基类类型,此时如果用typeid和dynamic_cast都会认为是基类类型,此时派生类是不可见的。

条款11:在operator=中处理“自我赋值”

  • 先copy一个备份,然后删除原来那个值,然后将备份赋值给新值。

条款17:以独立的语句将new对象置入智能指针

std::shared_ptr<Object> p = std::shared_ptr<Object>(new Object);
method(p, method2());  //1

method( std::shared_ptr<Object>(new Object), method2());  //2

上面代码2中由于编译器导致执行顺序问题:

  1. new Object
  2. method2()
  3. new shared_ptr

如果method2出现错误,那么new Object会成为废弃指针。


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

  • pass-by-reference可以避免切割问题:派生类实参以by-value形式传值给基类形参,此时会调用基类的copy构造函数,所以函数内只有基类,派生类的行为会被阉割掉,如:基类调用virtual成员函数就一定不会调用派生类的对应成员函数。
  • “尽量用pass-by-reference-to-const替换pass-by-value”这条规则对于内置类型以及stl的迭代器函数对象往往并不适用。

条款21:必须返回对象时,别妄想返回其reference

  • 绝对不返回pointer或reference指向一个local stack对象;会返回一个reference指向一个heap-allocted对象;或返回pointer或reference指向一个local static对象。

条款27:尽量少做类型转换

  • 下述代码将*this(派生类对象)转换为Base,再调用print函数,实际上调用了Base::print函数。而且要注意的是,它调用的并不是当前对象上的函数,而是*this对象的中的Base成分的一个副本。所以此时在Base::print函数对成员的修改并不会影响到*this对象的成员,他只是修改了Base的副本。
class Base {
public:
    Base() :b(1) {};
    virtual void print() { b = 2; cout << b << endl; }
protected:
    int b;
};

class Derived : public Base {
public:
    Derived() = default;
    void print()
    {
        static_cast<Base>(*this).print();
        cout << b << endl;
    }
};

int main()
{
    Derived d;
    d.print();
    return 0;
}

输出:

2
1

从输出可以看出,将*this对象转化为基类对象所做的修改不会对*this有影响。


条款28:避免返回handles(pointer, reference,iterator)

  • 类成员函数如果返回一个handles,并且这个handles指向某个private成员,那么就可以通过这个handles修改类中的private成员,非常不安全。如果非要返回这个一个handles,那么就应该返回一个const的handles

条款31:将文件间的编译依存关系降到最低

  • 如果一个文件修改了,那么直接include这个文件或者间接include这个文件的文件都会重新编译。间接include:C include B, B include A, C间接include A。
  • 定义某个类的指针或者引用并不需要该类的定义,只需提前声明该类就可以了。
  • 当声明一个函数用到另外一个类时,并不需要该类的定义,即使这个函数以by value形式传递
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值