高效C++:构造/析构/赋值

了解C++默认提供和调用的函数

  • 编译器会自动为每一个空类创建构造函数、拷贝构造函数、赋值运算符以及析构函数
  • 不要使用编译器自动创建的函数,要杜绝这种情况发生,自己编写这些函数

如果不想使用编译器自动生成的函数,要明确拒绝

  • 编译器默认提供的函数,不仅不能给编程带来便利,而且会给在某种情况下引入难以定位的bug,因此应该明确拒绝
  • 拒绝的方式就是明确声明该函数为私有且不提供函数体
    • 私有表示对权限的控制,防止外部在意想不到的情况下调用
    • 不提供函数体,是让编译器在链接的时候报错,明确提示你注意这个函数
class Uncopyable{
private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
}
//作为基类继承即可

为多态的基类声明virtual析构函数

  • 如果一个类中有一个虚函数,那么必须将析构函数也申明成虚函数,主要是防止资源泄露(使得析构从下向上依次执行)
  • 如果涉及的类不用于多态,那么就不要声明虚函数,因为虚函数的调用需要借助虚函数列表,调用的效率没有普通函数高
  • 如果不想一个类被实例化,那么就声明该类的虚函数为纯虚函数,且提供其实现
class AbstractClass
{
public:
    virtual ~AbstractClass();
}

AbstractClass::~AbstractClass()
{
    //函数实现
    //目的是进行资源释放
}

把异常消灭在析构函数中

  • 析构函数绝对不要吐出异常,这会导致资源部分释放的问题,析构函数中的异常一定要try...catch处理
  • 如果客户需要对某个操作做出反应,且有可能抛出异常,那么就需要提供一个普通函数执行该操作,这样设计的好处:
    • 提供普通函数给客户使用,且明确会抛出异常,使得用户有机会对异常做出合理的处理
    • 析构函数中检查资源释放的状态,做最后的处理
class DBConn
{
private:
    DBConnect dbc;
    bool closed;
public:
     void close()
    {
        dbc.close();
        closed = true;
    }
    
    ~DBConn()
    {
        if(!closed)
        {
            try
            {
                dbc.close();
            } catch(...) {
                //停止或记录
            }
        }
    }  
}
//解决close会跑出异常的可能

绝不在构造函数和析构函数中调用virtual函数

  • 看清楚描述,是构造函数和析构函数中不能调用虚函数;析构函数本身是可以设计成虚函数的,且在某些情况下,必须设计成虚函数
  • 在构造函数未执行完成之前,类的虚函数表未建立
  • 进入析构函数之前,类的虚函数表已经销毁,无法调用

让operator=返回一个reference to *this

好处:便于连续赋值,类似下面这种执行方式:

a = b = c = d //连续赋值
class Widget
{
public:
    Widget& operator+=(const Widget& rhs)
    {
        return *this;
    }
}

猜你喜欢

转载自www.cnblogs.com/chusiyong/p/11448264.html