0%

2 构造、析构、赋值运算

条款05:了解C++默默编写并调用哪些函数

  1. 如果自己没声明,编译器会自动声明(编译器版本)的copy构造函数copy assignment操作符析构函数。如果没有声明构造函数,编译器也会声明一个default构造函数
  2. 如果某个base classes将copy assignment操作符声明为private,编译器将拒绝为其derived classes生成一个copy assignment操作符。
  3. 如果一个类中有reference或pointer类型的数据。那么对于copy assignment操作符需要自己定义,而不是使用编译器生成版本。

条款06:若不想使用编译器自动生成的函数,就该明确拒绝

  1. 为了组织copying动作可以设计一个base class并且不予以实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Uncopyable 
    {
    protected:
    Uncopyable() {}
    ~Uncopyable() {}
    private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
    };

    class HomeForSale : private Uncopyable
    {
    // class不再声明copy构造函数或copy assignment操作符
    ...
    };
            这行得通,甚至是member函数或friend函数——尝试拷贝HomeForSale对象,编译器便试图生成一个copy构造函数和一个copy assignment操作符,生成版会尝试调用base class的对应函数,而调用被拒绝,因为拷贝函数是private。

条款07:为多态基类声明virtual析构函数

  1. 给base class一个virtual析构函数,此后删除derived class对象就会销毁整个对象。如果class不含virtual函数,通常表示意图不被做一个base class。
  2. 想实现出virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。它由一个vptrvirtual table pointer)指向一个由函数指针构成的数组,称为vtblvirtual table);每个带有virtual函数的class都有一个相应的vtbl。当对象调用virtual函数时,编译器在其中寻找适当的函数指针。给base classes一个virtual析构函数这个规则只适用于polymorphic带多态性质的)base classes身上。

条款08:别让异常逃离析构函数

  1. 对于析构函数中可能抛出的异常,由两种办法可以避免。一是如果抛出异常就结束程序,通常通过在析构函数调用abort抢先制不明确行为于死地;二是吞下它。
  2. 如果用户需要对某个操作函数运行期间的异常做出反应,应该提供一个普通函数来操作。然后在结束时析构函数来判断二重保险。

条款09:绝不在构造和析构过程中调用virtual函数

  1. 由于base class构造函数的执行更早于derived class构造函数,当base class构造函数执行时derived class的成员变量尚未初始化。如果此期间调用的virtual函数下降至derived classes阶层,那些成员变量尚未初始化,这将产生未定义行为。
  2. 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class。

条款10:令operator=返回一个reference to *this

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

  1. 如果operator=函数内的*this和赋值的来源是同一个对象,潜在的delete操作可能就摧毁了全部对象。因此需要注意在复制之前要么数据最好别删除,要么通过测试是否自我赋值。
  2. 在operator=函数内的替换方案最好是使用所谓的copy and swap技术。
    1
    2
    3
    4
    5
    Widget& Widget::operator=(Widget rhs)
    {
    swap(rhs);
    return *this;
    }

条款12:赋值对象时勿忘其每一个成分

  1. 当你编写一个copying函数,要确保复制所有local成员变量,且调用所有base calsses内的适当的copying函数。
  2. 对于为了消除复制代码的重复性,不该用copy assignment操作符调用copy构造函数,反之亦然。消除重复代码的做法是,建立一个新的成员函数给两者调用。这样的函数往往是private而且被命名为init。