2012-02-04 59 views
3

我最近讀,Rule of three,我想知道我是否違反了它?我違反三條規則嗎?

在我的GUI應用程序,類,如MainFrameInterfaceCircuitBreadboard等(類名指示)有他們每個人的單個實例。在他們的構造函數中,我已經分配了一些資源(內存),我可以在它們的析構函數中安全地釋放它們。

所以我只定義了析構函數,但不拷貝構造函數賦值運算符

我確定我不需要它們,但是我很好奇如果我違反規則,以及我能做什麼來遵循它?

回答

6

三條規則約交易與所有三巨頭,但這並不一定意味着如果你不想要,你必須定義它們。要麼你提供他們,要麼你禁止他們。你不應該做的就是忽略它們。


所以我只定義了析構函數,而不是拷貝構造函數和複製操作。
我違反了三條法則嗎?

是的,你違反了規則。編譯器將生成一個拷貝構造函數和拷貝賦值操作符,並且由於您在構造函數中分配了內存並在析構函數中釋放,所以這些拷貝將具有錯誤的語義:它們將複製指針,並且將有兩個類別別名相同的內存。該分配甚至不會釋放舊的內存,而只是覆蓋指針。

這是問題嗎?

如果,像你這樣的暗示,你不進行復印或分配到這些類的實例,不會出錯。但是,最好保證安全,並且聲明(甚至不要打擾)複製構造函數和複製賦值運算符private,所以不會意外調用它們。

在C++ 11可以使用= delete語法來代替:

T(T const&) = delete; // no copy constructor 
T& operator=(T const&) = delete; // no copy assignment 
+0

第一個說法解決了我的疑問。 '= delete'看起來是一個很好的解決方案,只是告訴我這兩個原型是否應該是私有的(除了'= delete') – 2012-02-04 07:22:03

+0

@Vinayak:如果你使用'= delete',那麼它們是沒有關係的是公共的還是私人的。 – 2012-02-04 07:25:52

+0

+1爲所有偉大的答案! – 2012-02-04 07:27:33

2

您應該聲明(但不執行)的私人拷貝構造函數和賦值操作符。確保你沒有實現這些功能。這將防止任何類型的不應複製的類的複製。

+2

非空功能。你應該聲明它們是私有的,永遠不要指定任何實現。如果您的代碼最終複製/分配對象,這將保證失敗。 – StilesCrisis 2012-02-04 07:15:23

+0

請關注@StilesCrisis,關注。相應地編輯你的答案 – 2012-02-04 07:28:51

+0

我只記得我現在可以編輯。我修復了它。 – StilesCrisis 2012-02-04 07:35:30

1

是的,它確實違反了三定義的規則。

然而,這是一個「經驗法則」。一般指導原則。如果您不需要複製構建或分配操作,請不要實施它們。其他人則建議宣佈它們是私人的,並將它們定義爲空的。我會更進一步說甚至沒有定義它們。

如果你定義它們,那麼你仍然可能會調用空方法。相反,將它們留在未定義的位置,如果您嘗試調用這些方法,您將收到鏈接器錯誤,因爲找不到方法定義。在運行時錯誤/不希望的行爲上贊成構建時錯誤。

2

這很大程度上取決於您的應用程序邏輯以及您如何將用戶的接口類記錄在文件中。

正常情況下,一個好的C++程序員必須知道三個規則(如果你知道「複製和交換習慣用法」,那麼你應該知道一半),在C++ 11中移動語義)。

如果您的班級管理資源,並且如果同一班級是可複製的(即複製ctor和assigment操作員沒有定義爲私人),那麼通過編寫您自己的copy ctor和assignment operator來進行深層複製非常重要。

但是,如果你總是把你的課程作爲REFERENCE傳給他們,那麼最好定義一個默認的copy ctor和賦值運算符爲private,這樣即使你通過valy或錯誤地複製,編譯器也會警告你。

1

如果你不需要它,不要關注它。三條規則背後的動機是,當你需要析構函數時,通常是因爲你需要做一些動態釋放。

如果您還要執行釋放操作,那麼您還需要複製構造函數和賦值操作符。想象一下,你有一個具有指針的東西類:

struct Foo 
{ 
    Foo() { ptr_ = new int; } 
    ~Foo() { delete ptr_; } 
    int* ptr_; 
}; 

因爲你沒有定義拷貝構造函數和賦值運算符,只要你犯了一個Foo的副本,原件和複印件將同時使用指向相同的指針int;當原始或副本被破壞時,指針被釋放,而另一個則不能使用數據。

Foo(cont Foo& other) { 
    other.ptr_ = new int(*ptr_); 
} 

// Same for operator= 

如果你沒有在你的構造函數/析構函數做任何動態分配,有你實際上並不需要一個拷貝構造函數或賦值操作符(但不一定是)一個很好的機會。

相關問題