C++类禁止copy构造函数和copy assign操作符

时间:2021-08-24 19:27:24

C++类禁止copy构造函数和copy assign操作符

在C++类中,编译器可以暗自为class创建default构造函数、copy构造函数、copy assignment操作符,以及析构函数。注意,这些编译器产生出来的函数都是public的,为了阻止这些函数被创建出来,我们可以把它们声明为private,这样就阻止了编译器暗自创建其对应版本函数。

class Node  
{  
public:  
    Node(int _data = 0) : data(_data) {}  
    int get() const { return data; }  
    void set(int _data) { data = _data; }  
  
private:  
    Node(const Node &);  
    Node &operator=(const Node &);  
  
    int data;  
};  

在上面的class定义中,当程序企图拷贝Node对象时,编译器就会阻止该操作。这样的话,只要将copy构造函数和copy assign操作符声明为private就可以了,还有另外一种方式,我们可以专门定义一个阻止copying动作的base class。这个base class如下所示:

class Uncopyable  
{  
protected:  
    Uncopyable() {} // 允许derived对象构造和析构  
    ~Uncopyable() {}  
private:  
    Uncopyable(const Uncopyable &); // 阻止copying  
    Uncopyable &operator=(const Uncopyable &);  
};  
  
class Node : private Uncopyable  
{  
public:  
    Node(int _data = 0) : data(_data) {}  
    int get() const { return data; }  
    void set(int _data) { data = _data; }  
  
private:  
    int data;  
};  

这样的话,在程序中,甚至在member函数或friend函数中,尝试拷贝Node对象,编译器就会试着生成一个copy构造函数或copy assign操作符,这些函数的“默认版本”会尝试调用其base class的对应函数,但是这些调用会被阻止,因为它们是private的,即阻止了该类对象的copy操作。

参考资料:

【1】 《Effective C++ 第3版》 条款6


而通过阅读开源代码学习可以使用宏定义来禁止class的拷贝构造函数和赋值构造函数(以下代码源于Apollo/modules/common/macro.h)

宏定义 DISALLOW_COPY_AND_ASSIGN:

#define DISALLOW_COPY_AND_ASSIGN(classname) \
private:                                   \
    classname(const classname &);             \
    classname &operator=(const classname &);

用于在C++中禁止class的拷贝构造函数和赋值构造函数,良好的c++代码应该主动管理这2个操作符。

在caffe、cartographer和Apollo或者其他的著名库中均有类似的操作。


宏定义 DISALLOW_IMPLICIT_CONSTRUCTORS:

#define DISALLOW_IMPLICIT_CONSTRUCTORS(classname) \
private:                                         \
    classname();                                    \
    DISALLOW_COPY_AND_ASSIGN(classname);

禁止class的无参构造函数。


宏定义 DECLARE_SINGLETON:

#define DECLARE_SINGLETON(classname)        \
public:                                    \
    static classname *instance() {            \
    static classname instance;              \
    return &instance;                       \
}                                         \
DISALLOW_IMPLICIT_CONSTRUCTORS(classname) \
    private:

单例类定义,instance() 返回指向同一个class对象的指针。禁止拷贝/赋值运算符。