[Reading Notes] Effective C++(02) Construction/Destruction/Assignment

Keywords: C++ Database

Author: LogM

This article was originally published in https://segmentfault.com/u/logm/articles , no reloads allowed~

2. Construction/Destruction/Assignment

  • 2.1 Clause 05:C++ automatically writes default constructs, copy constructs, destructors, assignment functions

    //You thought you wrote an empty class without code
    class Empty{};
    
    // In fact, C++ automatically generates many functions
    class Empty{
    public:
        Empty() {...}    //Default constructor
        Empty(const Empty& rhs) {...}    //copy constructor
        ~Empty() {...}     //Destructor
    
        Empty& operator=(const Empty& rhs) {...}    //Mutator
    };
  • Section 06 of 2.2: Declare as private to prevent automatically generated functions from being used

    //Declare copy constructors and assignments as private s to prevent them from being used
    class Empty {
    public:
        ...
    private:
        ...
        Empty(const Empty&);
        Empty& operator=(const Empty& rhs);
    };
  • Section 07 of 2.3: Destructors for base classes must be virtual when using polymorphic attributes

      //A polymorphic scene
      class TimeKeeper {   //Timer (base class)
      public:
          TimeKeeper();
          virtual ~TimeKeeper();
          ...
      };
      class AtomicClock: public TimeKeeper {...}    //atomic clock
      class WristWatch: public TimeKeeper {...}    //Wrist Watch
    
      //This is often the case with polymorphic attributes
      TimeKeeper* ptk = getTimeKeeper();
      ...
      delete ptk;

    Above is a scenario using polymorphism, when delete ptk, because PTK is of TimeKeeper type, if the base class destructor is not virtual, then only the base class destructor is called for the destructor of ptk, which is incorrect; using virtual ~TimeKeeper(); ensuring that the correct subclass destructor is called for the PTK destructor

    If a class has a virtual function, indicating that it may be used for polymorphism, then there should be a virtual destructor.

    Do not use polymorphic attributes on classes of non-virtual destructors, including STL containers such as string s and vector s.

    Classes with virtual functions generate vtbl (virtual table) to determine which function to call at run time, which is pointed at by vptr (virtual table pointer), and takes up space.Declaring virtual randomly increases volume.

  • 2.4 clause 08: Destructors should not throw exceptions

    • The destructor throws an exception and the program terminates the destructor, resulting in a partial release of resources.
        //Typical scenarios for managing database connections
        //If so, the destructor may throw an exception
        class DBConn {
        public:
            ...
            ~DBConn() {
                db.close();
            }
        private:
            DBConnection db;
        }
    
        //Catch exceptions within destructors and do not let them throw
        class DBConn {
        public:
            ...
            ~DBConn() {
                try { db.close(); }
                catch (...) {
                    ...
                }
            }
        private:
            DBConnection db;
        }
  • Section 09 of 2.5: Do not use virtual functions in constructors and destructors

    • When the constructor constructs, the member variables of the derived class are not initialized, and the virtual function points to the base class.
    • When a destructor destructs, the member variables of the derived class are partially destructed, and the virtual function points to the base class.
  • Section 10 of 2.6: Make operator = return value reference to *this

    • This is done to achieve continuous assignments
    int x, y, z;
    x = y = z = 1;   //continuous assignment
    
    int& operator=(const int& rhs) {
        ...
        return *this;   //Returns a reference to the left object
    }
  • 2.7 Clause 11: Handling self-assignment in operator=

    //The following code, error if self-assignment occurs
    Widget& Widget::operator=(const Widget& rhs) {
        delete elem;
        elem = new Bitmap(*rhs.elem);
        return *this;
    }
    
    //Method 1
    Widget& Widget::operator=(const Widget& rhs) {
        if (this == &rhs) { return *this; }
    
        delete elem;
        elem = new Bitmap(*rhs.elem);
        return *this;
    }
    
    //Method 2
    Widget& Widget::operator=(const Widget& rhs) {
        Bitmap* pOrig = elem;
        elem = new Bitmap(*rhs.elem);
        delete pOrig;
        return *this;
    }
  • Section 12 of 2.8: Do not omit member variables from copy construction and assignment functions

    • The compiler does not check whether copy constructs and assignment functions copy all member variables;
    • Copy construction and assignment functions for derived classes remember to call copy construction and assignment functions for the base class first.

Posted by pillot1005 on Sat, 18 May 2019 11:31:23 -0700