2013-01-07 166 views
1

在下面的代碼中,類B的析構函數在情況1中調用,但在情況2中調用時,執行從fn()返回到main。我不明白這個區別,因爲當A被創建爲new時,它們都在堆內存中。你能解釋一下嗎?析構函數被調用

class B { 
public: 
    B() { 
     printf(" [B] COntsructor"); 
    } 
    ~B() { 
     printf(" [B] Destructor"); 
    } 
}; 

class A { 
public: 
    A() { 
     printf(" [A] COntsructor"); 
    } 
    ~A() { 
     printf(" [A] Destructor"); 
    } 

    B Query() { return b; } /// Case 1 
    B* Query() { return &b; } /// Case 2 

    B b; 
}; 

void fn() 
{ 
    A *a = new A(); 
    B b = a->Query(); // case 1 
    B* b = a->Query(); // case 2 
    return; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    fn(); 
    return 0; 
} 
+1

你有兩種情況1,情況2在代碼中,令人困惑... – billz

+0

當你按值返回時,你必須構造一個值來返回。 –

+0

@billz我認爲每個案例都涉及到評論對中的另一行。 –

回答

3

案例1:當你按值局部變量b返回b使用拷貝構造函數構造。除了一個副本外,其他所有副本都會被Return Value Optimization優化。局部變量b的破壞會觸發析構函數。

案例2:當您返回&b你正在返回一個指針b等有沒有必要破壞。

編輯:The code顯示析構函數被調用時沒有相應的構造函數調用。這是因爲函數返回拷貝是通過拷貝構造函數發生的。

編輯2:@ZarShardan是正確的 - 我提到的「許多副本」可能不存在,這要歸功於Return Value Optimization

+0

我在本質上認爲只有本地副本被破壞,但B的構造函數只被調用一次,然後調用B的析構函數。那堆上的A的成員變量呢? – user1862187

+0

@ user1862187成員變量是被返回的成員變量,當它由值返回時,它在堆棧上作爲函數'a-> query'的返回值進行復制。這個副本的銷燬就是調用析構函數。 –

+1

啊......複製構造函數被調用。 – user1862187

-1

對象a永遠不會被刪除,所以它自己的析構函數和其成員對象的析構函數都不會被調用。

嘗試在函數fn()

或更好的使用std ::的unique_ptr而不是裸指針的末尾添加

delete a; 

。這是更好的設計,以防您的查詢成員函數拋出異常(RAII填充)

+1

而有效的建議,而不是問題的答案,應該是一個評論。 –

+0

爲什麼downvote?我解釋了爲什麼不調用析構函數:對象a(因此它的所有成員也是)構建在堆上,並且從不刪除。我還指出這是一個相當嚴重的問題(在C++世界中) - 內存泄漏,然後進行編輯以添加更好的方式來處理這個問題。雖然可能不是一個非常全面的答案,但它仍然是正確的,並增加了該主題的價值。無論哪種方式不應該得到一個downvote。 –

0

在第二種情況下,我看不到您在B中創建new實例,因此A作爲成員持有的指針將被清理由於A的析構函數和B中的構造函數從未被調用過,所以析構函數也不會被調用。

1
  • a永遠不會被刪除,所以沒有它或其成員的析構函數。
  • a->b將使用默認構造函數構造,所以這是您看到的構造函數調用。
  • B b = a->Query();將使用複製構造函數創建,該構造函數不會打印任何內容。
  • fn結束時,本地b將超出範圍,因此這是您的析構函數調用。如果你的拷貝構造函數添加調試代碼,如果你有所有的調試代碼打印this

事情可能變得更加清晰,如果你最終刪除a看到那些析構函數調用爲好。

+0

是的,謝謝...複製構造函數invloked – user1862187

相關問題