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對象的指針。禁止拷貝/賦值運算符。