2013-05-02 47 views
9

所以在下面的例子中,我們導致類Foo*this = Foo()代替。我很高興我剛剛測試過這個,因爲在這種情況下,舊的Foo的析構函數沒有被調用。我想這是因爲默認賦值運算符只是使用memcpy ......但是作爲語言設計問題...爲什麼不讓默認賦值運算符首先銷燬指定對象以防止意外?爲什麼默認的賦值操作符沒有先調用析構函數?

http://codepad.org/9WCo6yZ5

#include <iostream> 
using namespace std; 

class MustBeDestroyed //(for some reason not shown here) 
{ 
public: 
    int i; 
    MustBeDestroyed(int i) : i(i) {} 
    ~MustBeDestroyed() { cout << "destroyed contained class " << i << endl; } 
}; 

class Foo 
{ 
public: 
    MustBeDestroyed x; 
    Foo(int y) : x(y) {} 
    void replace_myself(int y) { Foo f(y); *this=f; } 
    void print() { cout << "This is outer/inner class " << x.i << endl; } 
    ~Foo() { cout << "destroyed outer class " << x.i << endl; } 
}; 

int main() 
{ 
    Foo a(1); 
    a.print(); 
    a.replace_myself(2); 
    a.print(); 
    return 0; 
} 
+2

什麼意外?賦值就是這樣 - 爲舊值分配一個新值。 – 2013-05-02 14:47:06

+1

默認賦值運算符不使用memcpy(儘管編譯器優化可能會導致這種情況)。這是一項成員任務。 – huskerchad 2013-05-02 14:48:49

+1

'int i,j;我= 5; j = i;'你是不是說我期望不再使用'i'是明智的?我不同意。 – Fiktik 2013-05-02 14:51:38

回答

1

規則爲什麼會指派調用析構函數?它的確如它所說的那樣做:它調用賦值運算符。編譯器生成的賦值運算符很簡單:將所有成員從舊對象分配給新對象(使用它們的賦值操作)。沒有更多,沒有更多。這正是着名的rule of three的原因。

現在至於爲什麼它不調用析構函數:這將結束對象的生命週期。儘管在理論上可能在舊的物體上構建一個新的物體,但這種方法在異常(look at this question for more about that)中通常是不正確的,因此它在一般情況下不能使用。此外,如果它採用了你提出的方法,它不會爲成員調用賦值運算符,而是調用析構函數/拷貝構造函數。這意味着自定義分配行爲(實際上並不需要與複製行爲相同)不會受到尊重。

+1

如果被覆蓋的值包含一個ptr到堆中的數據,分配將首先調用析構函數以避免內存泄漏。如果你簡單地覆蓋ptr,那麼你會泄漏內存。因此,在這種情況下內置的賦值運算符應該被覆蓋(因爲內置的將會泄漏)。 – wcochran 2016-02-09 04:44:15

6

由於第一銷燬對象將結束壽命。然後你將不得不調用一個構造函數來啓動新對象的生命週期。但是operator =的行爲不是破壞當前對象並創建另一個對象,而是爲現有對象分配一個新值。

基本上,你違反了3

相關問題