2011-04-18 41 views
20

有時需要禁止C++類中的拷貝構造函數,以便類變爲「不可拷貝」。當然,operator=應該同時被禁止。在C++中禁止拷貝構造函數的最可靠方法是什麼?

到目前爲止,我見過兩種方式來做到這一點。方法1是申報方法私有,並給它沒有實現:

class Class { 
//useful stuff, then 
private: 
    Class(const Class&); //not implemented anywhere 
    void operator=(const Class&); //not implemented anywhere 
}; 

方式二是申報方法私有,並給它「空」的實施:

class Class { 
//useful stuff, then 
private: 
    Class(const Class&) {} 
    void operator=(const Class&) {} 
}; 

IMO第一個是更好的 - 即使有一些意想不到的原因導致從同一個類成員函數調用拷貝構造函數,稍後會出現鏈接器錯誤。在第二種情況下,直到運行時纔會忽略這種情況。

第一種方法有什麼嚴重的缺點嗎?什麼是更好的方式,如果有的話,爲什麼?

+4

http://www.boost.org/doc/libs/1_46_1/boost/noncopyable.hpp – dgnorton 2011-04-18 11:28:17

回答

16

第一種方法是Boost如何解決它(source code),據我所知,沒有缺點。事實上,鏈接器錯誤是該方法的一大優點。您希望錯誤發生在鏈接時,而不是在您的客戶端執行代碼時突然崩潰。

如果您使用的是Boost,您可以節省一些鍵入。這確實與您的第一個例子:

#include <boost/utility.hpp> 

class Class : boost::noncopyable { 
// Stuff here 
} 
+7

雖然它可能是「Boost如何解決它」,但在基類中以這種方式解決它並在自己的類中自行完成之間仍然存在顯着差異,因爲基類方法更加自我記錄,從而避免了某些人之後不小心將它添加到課程中,認爲它沒有被錯誤地實現。 – 2011-04-18 11:51:16

+0

這仍然是一個很好的情況,因爲它可以讓你在他們造成真正的傷害之前抓住那個人。當然,你不能指望小輩們知道這一點,但是他們不應該在沒有複習的情況下做出這樣的改變。 – MSalters 2011-04-18 12:41:55

+0

@Tony:我更喜歡boost替代方案(或者不能使用boost時的另一個自定義類)。它更容易理解,更具可讀性,並且錯誤消息更好一些。 – 2011-04-18 14:54:51

25

第一個是更好

更妙的是C++0x 'delete' keyword

class Class { 
// useful stuff, then 
public: 
    Class(const Class&) = delete; 
    void operator=(const Class&) = delete; 
}; 
+6

@sehe:有了'delete',沒有理由將它設爲私有。事實上,它在公共界面中出現似乎更好,用戶明智。 – 2011-04-18 12:01:49

+0

好點。更新 – sehe 2011-04-18 12:02:54

+0

@Matthieu在這種情況下使用'delete'是C++ 11;如果你不得不針對任何較老的編譯器,甚至更多更新的編譯器,你不能使用它。 – 2011-04-18 13:21:19

7

你總是可以從boost::noncopyable繼承。

否則我從來沒有見過理由2號比1號更好,因爲它可以讓你在朋友或類方法中「複製構造」一個​​對象,即使它不會真正創建對象的真實副本。

2

。在你的第一種方法不是缺點,我已經使用,爲了使「不可複製」級..

3

至於其他的答案中建議別的東西,並沒有真正試圖回答這個問題,所以這裏是我的嘗試:

那麼哪種方法更好?這取決於你如何定義禁止複製

如果您想防止其他人(只有非朋友類和功能)複製,同時允許朋友和會員功能複製,那麼第二種方法是要走的路。

如果您想防止大家(朋友,非朋友,會員功能)複製,那麼第一種方法是唯一正確的解決方案。

請注意,第二種方法不會阻止朋友和成員函數複製(即從調用複製函數)

1.如果你沒有正確地在第二種情況下定義它們,然後複製將無法正常工作,如預期,但是這是一個不同的事情完全。但問題是第二種情況並不妨礙調用複製函數。編譯器不會生成任何錯誤消息。

1

我個人認爲你已經回答了你自己的問題,應該使用第一種方法。

如果你不希望它是可複製的,就像你說的那樣會拋出鏈接錯誤。但是,如果你使用第二種方法,並且你最終偶然使用拷貝構造函數,它會編譯並運行;你完全沒有跡象表明不一致性來自何處,直到你打開一個調試器。或者如他所說,如果你可以使用現代編譯器,使用C++ 11的'= delete'表示法。