[effective c++] Construction and destruction

Item 7. Declare virtual destructors for polymorphic base classes
Car *c = new YellowCar();
delete c;

c points to an object of YellowCar, but c is a pointer to Car. If the destructor of Car is not a virtual function, then only the destructor of Car will be called when deleting. If there is dynamically allocated memory in YellowCar, the release logic of this piece is usually completed in its destructor. When deleting, the destructor of YellowCar cannot be called, which causes a memory leak.
However, it should be noted that if polymorphism is not used, that is to say, there is no virtual function in the base class, and the destructor of the base class is declared as virtual, this approach is not good. First, the virtual function needs to be accessed through the virtual function table pointer, and the virtual table pointer occupies the space of the object. Secondly, the type conversion will bring uncertainty. Therefore, there is no need to superfluous.

Item 8, don’t let exceptions escape the destructor

Conversely, when the doSomething function finishes executing, it will start to deconstruct each Widget object stored in the container v. However, the object destructor may spit out an exception. In this case, an abnormal number of objects in the container will be spit out, which will lead to uncertainty in the operation of the program .

class Widget {
    
    
public:
    //......
    ~Widget() {
    
        // 假定这个析构函数可能会吐出异常
        //......
    }
    //......
};

void doSomething()
{
    
    
    //......
    std::vector<Widget> v;
    //......
}

The correct method to use , handle the exception in the destruction, instead of letting it throw

// 修改后的DBConn类实现
class DBConn {
    
    
public:
    //......
    void close() {
    
        // 要求用户自己关闭数据库对象
        db.close();
        closed = true;
    }
    //......
    ~DBConn() {
    
    
        if (!closed) {
    
        // 如果用户忘记了这么做,就采用 try catch 机制吞下异常。
            try {
    
    
                db.close();
            }
            catch (...) {
    
    
                // 记录此次 close 失败
                //......
            }
        }
    }
    //......
private:
    //......
    DBConnection db;
    bool closed;    // 增设此变量用以判断用户是否已经自行调用 close(),用户也可根据此变量判断 close() 是否顺利执行并作出相应的异常处理。
    //......
};
Item 9. Do not call virtual functions in constructors and destructors
class Transaction {
    
    // 所有交易的基类
public:
 Transaction();
 virtual void logTransaction() const = 0;//建立依赖于具体交易类型的登录项
 ...
};
Transaction::Transaction() //实现基类的构造函数
{
    
     
 ...
 logTransaction(); //最后,登录该交易
} 
class BuyTransaction: public Transaction {
    
     
// 派生类
public:
 virtual void logTransaction() const; //怎样实现这种类型交易的登录? 
 ...
};
class SellTransaction: public Transaction {
    
     
//派生类
public:
 virtual void logTransaction() const; //怎样实现这种类型交易的登录?
 ...
};

During the construction of the base class, virtual function calls are never passed to the derived class. Instead, the derived class object behaves as if it is the base type itself. In layman's terms, virtual functions are not "constructed" during the construction of the base class.
Because the base class constructor is executed before the derived class, the data members of the derived class have not been initialized when the base class constructor is running. If the virtual function call is passed to the derived class during the construction of the base class, the derived class object can of course refer to the local data members, but these data members have not been initialized yet. This will lead to endless undefined behavior and overnight code debugging.
Once the destructor of a derived class runs, the derived data members of the object are assumed to be undefined values, so C++ treats them as if they do not exist. Once in the destructor of the base class, the object becomes a base class object, and all parts of C++ (virtual functions, dynamic_cast operators, etc.) are handled in this way.

Guess you like

Origin blog.csdn.net/niu91/article/details/112862868