2012-02-17 62 views
1

我有以下示例代碼。類bar源自基類foo併爲ptr_x分配內存,同時通過基類授予讀取/寫入訪問權限。這是一個大型代碼的玩具模型,其中讀/寫函數對於對象的所有不同變體都是相同的,但是在不同的變體中內存分配略有不同。在基類中的運算符定義

#include <iostream> 

class foo{ 
protected: 
    int *ptr_x; 

public: 
    foo(){ 
     std::cout << " 1) Inside foo constructor: " << ptr_x << std::endl; 
    } 

    void read() 
    { 
     std::cout << " 2) Inside read function: " << ptr_x << std::endl;  
     std::cout << " 3) Inside read function: " << *ptr_x << std::endl; 
    } 
    void operator=(const int rhs) 
    { 
     std::cout << " 4) Inside operator= : " << ptr_x << std::endl; 
     *ptr_x = rhs; 
    }   
}; 
class bar: public foo{ 

public: 
    bar(int a) 
    : foo() 
    { 
     std::cout << " 5) Inside bar constructor: " << ptr_x << std::endl; 
     ptr_x = new int; 
     std::cout << " 6) Inside bar constructor: " << ptr_x << std::endl; 
     *ptr_x = a; 
    } 
    ~bar() 
    { 
     std::cout << " 7) Inside bar destructor: " << ptr_x << std::endl; 
     if (ptr_x != NULL) {delete ptr_x; ptr_x = NULL;} 
    } 
}; 
int main(){ 
    bar a(20); 
    a.read(); 
    a = 40; 
    a.read(); 
    return 0; 
} 

當我運行代碼,我得到:

1) Inside foo constructor: 0 
5) Inside bar constructor: 0 
6) Inside bar constructor: 0x1d8f010 
2) Inside read function: 0x1d8f010 
3) Inside read function: 20 
1) Inside foo constructor: 0x7f40c11e3b68 
5) Inside bar constructor: 0x7f40c11e3b68 
6) Inside bar constructor: 0x1d8f030 
7) Inside bar destructor: 0x1d8f030 
2) Inside read function: 0x1d8f030 
3) Inside read function: 0 
7) Inside bar destructor: 0x1d8f030 
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000001d8f030 *** 

我有以下幾個問題:1)爲什麼不代碼輸入的基類operator=? 2)爲什麼第二次調用構造函數/析構函數? 3)爲什麼會出現double free問題?

我究竟做錯了什麼?

編輯:好的double free問題是顯而易見的,但爲什麼會出現相同的內存位置的兩個實例?這不知何故與operator=有關,因爲當我評論它一切都很好。

由於

回答

2

推理所觀察到的行爲:

編譯器使用在派生類的轉換構造,

bar(int a) 

評價:

a = 40; 

這需要在整合er 40,並使用轉換構造函數創建bar對象,然後使用編譯器爲類bar生成的隱式複製賦值運算符(=)將創建的bar對象指定給a

這就是您看到對bar構造函數的額外調用以及從未調用基類重載=的原因。另外,對於雙自由就在於這裏的原因,你有多個bar對象,其保持指向分配給ptr_x和動態內存當對象的一個​​超出範圍的析構函數被調用這將釋放內存,但離開其他對象中的成員指針處於懸掛狀態。

如何解決這些問題:
你應該標記轉換構造explicit,如果你不想讓編譯器使用它這樣的隱式轉換。

您應該遵循Rule of Threebar類。

警告:
。注意,在基類的操作者=總是由隱式生成=操作者派生類隱藏。

+0

謝謝。這是否意味着我總是必須爲派生類定義'='運算符?什麼是運營商是這樣的? – GradGuy 2012-02-17 06:44:39

+0

@GradGuy:如果你不爲你的派生類重新定義'='運算符,編譯器會隱式生成它,從而隱藏基類'='。閱讀更多關於[功能隱藏](http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9)的信息,這應該能讓你很好地瞭解相同情況的適用情況。 – 2012-02-17 07:04:53

1

對於你剛纔應該申報 bar (int a)的第一個問題是

explicit bar(int a). 

這給出了一個合適的編譯錯誤類酒吧應該有=運營商定義的。