2016-08-12 38 views
1

我的C的簡化版本++類:顯式析構函數調用不工作

我的單元測試的
class Class 
{ 
public: 
    Class(uint32_t size_, uint8_t val_) buf(NULL), size(size_) 
    { 
     buf = new uint8_t[size]; 
     memset(buf, val_, size); 
    } 
    ~Class() 
    { 
     if(buf != NULL) 
     { 
      delete[] buf; 
      buf = NULL; 
      size = 0; 
     } 
    } 
    void FakeDtor() 
    { 
     if(buf != NULL) 
     { 
      delete[] buf; 
      buf = NULL; 
      size = 0; 
     } 
    } 

    protected: 
     uint8_t* buf; 
     uint32_t size; 
} 

代碼:

TEST_F(Classtest, testDestructor) 
{ 
    Class *buff = new Class(10,10); 
    ASSERT_NE(buff->getData(), (uint8_t*)NULL); 

    buff->~Class(); // buff->FakeDtor(); 

    ASSERT_EQ(buff->getData(), (uint8_t*)NULL); 
} 

當我使用的MSBuild編譯代碼並運行UT - 顯式調用析構函數工程和UT通行證。當我使用g ++編譯並使用gtest運行UT時 - 顯式調用dtor似乎失敗了,因爲在斷言失敗後。當我使用FakeDtor()而不是〜Class()時,UT在Windows和Linuix上同時通過。當在Linux下調用它時,什麼會導致dtor不執行?

+0

你不能直接調用析構函數。 如果你不想銷燬該對象使用'刪除' –

+0

@JonasJuffinger是的,你可以。但你通常不應該。 –

+0

@JonasJuffinger:允許手動調用析構函數。這是一種正常的操作,特別是如果您使用new-at操作符來創建對象。 – Klaus

回答

2

在其非平凡的析構函數運行後,讀取類的內容會調用未定義的行爲。對象所在的內存仍然存在並不重要,因爲你沒有對象,對象本身已經死了,不能再使用。

從字面上看,一切都可以發生,如果你反正做。這個概念類似於懸掛指針/參考,例如參見this

這個UB包含「如果析構函數設置數據成員值,由於沒有有效的程序將永遠無法讀取這些值,編譯器可以優化這些成員的設置。,正如@hvd在他的comment中指出的那樣。

+1

其中,由於OP對於OP而言可能並不明顯,這意味着如果析構函數設置了數據成員值,由於沒有有效的程序將永遠無法讀取這些值,編譯器可以優化這些成員的設置。 – hvd

+0

@ hvd:在一個實際上處於破壞狀態的對象中操縱數據的意義是什麼? – Klaus

+0

@Klaus這些操作的所有可觀察的副作用都必須發生。儘管分配給內置類型沒有副作用,但總是多餘的。 –