2010-05-11 65 views
2

嘿,我在鼓機上工作,並且遇到矢量問題。Double添加到矢量中的免費內部析構函數

每個序列都有一個樣本列表,樣本在向量中排序。但是,如果樣本是向量上的push_back,則將調用樣本的析構函數,並導致雙重空閒錯誤。

下面是創建樣品的編號:

class XSample 
{ 
    public: 
    Uint8 Repeat; 
    Uint8 PlayCount; 
    Uint16 Beats; 
    Uint16 *Beat; 
    Uint16 BeatsPerMinute; 

    XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat); 
    ~XSample(); 

    void GenerateSample(); 

    void PlaySample(); 
}; 

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat) 
{ 
    Beats = NewBeats; 
    BeatsPerMinute = NewBPM; 
    Repeat = NewRepeat-1; 
    PlayCount = 0; 

    printf("XSample Construction\n"); 
    Beat = new Uint16[Beats]; 
} 

XSample::~XSample() 
{ 
    printf("XSample Destruction\n"); 
    delete [] Beat; 
} 

和 '發電機' 代碼創建向量中的每個樣品:

class XDynamo 
{ 
    public: 
    std::vector<XSample> Samples; 

    void CreateSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat); 
}; 

void XDynamo::CreateSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat) 
{ 
    Samples.push_back(XSample(NewBeats,NewBPM,NewRepeat)); 
} 

這裏是主():

int main() 
{ 
    XDynamo Dynamo; 

    Dynamo.CreateSample(4,120,2); 
    Dynamo.CreateSample(8,240,1); 

    return 0; 
} 

這是程序運行時發生的情況:

Starting program: /home/shawn/dynamo2/dynamo 
[Thread debugging using libthread_db enabled] 
XSample Construction 
XSample Destruction 
XSample Construction 
XSample Destruction 
*** glibc detected *** /home/shawn/dynamo2/dynamo: double free or corruption (fasttop): 0x0804d008 *** 

但是,當刪除[]從析構函數中刪除時,程序運行完美。

這是什麼造成的?任何幫助是極大的讚賞。

+1

你爲什麼不只是使用' 'XSample'中的矢量'? – GManNickG 2010-05-11 20:14:29

+0

同意,'Beat'應該是一個向量。 – Bill 2010-05-11 21:17:45

回答

3

問題是你在對象中動態分配內存,但沒有聲明拷貝構造函數/賦值操作符。當你分配內存並負責刪除它時,你需要定義編譯器生成的所有四個方法。

class XSample 
{ 
    public: 
     // Pointer inside a class. 
     // This is dangerous and usually wrong. 
     Uint16 *Beat; 
}; 

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat) 
{ 
    // You allocated it here. 
    // But what happens when you copy this object or assign it to another variable. 
    Beat = new Uint16[NewBeats]; 
} 

XSample::~XSample() 
{ 
    // Delete here. Turns into double delete if you don't have 
    // copy constructor or assignment operator. 
    delete [] Beat; 
} 

當你發生了什麼上面:

XSample a(15,2,2); 
XSample b(a); // Copy constructor called. 
XSample c(15,2,2); 

c = a; // Assignment operator called. 

兩種方式來解決這個問題:

  1. 創建拷貝構造函數/賦值運算符。
  2. 使用另一個爲您進行內存管理的對象。

我會使用解決方案2(因爲它更簡單)。
它也是一個更好的設計。內存管理應該由他們自己的班級來完成,你應該專注於你的鼓。

class XSample 
{ 
    public: 
    std::vector<Uint16> Beat; 
}; 

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat): 
     Beat(NewBeats) 
{ 
     // Notice the vector is constructed above in the initializer list. 
} 

    // Don't need this now. 
XSample::~XSample() 
{ 
} 

如果你想這樣做艱難地:
Dynamically allocating an array of objects

如果你想看到什麼編譯器版本看這裏:
C++ implicit copy constructor for a class that contains other objects

2

編譯器添加了一個默認的拷貝構造函數,這意味着XSample::Beatssamples.push_back(...)期間有別名。您應該添加一個可以正確初始化XSample的複製構造函數,可能是通過從參數中複製XSample::Beats

2

向量是複製構造您的XSample s(使用編譯器生成的默認拷貝構造函數),並因此導致副本破壞時出現問題。你可以在向量中存儲指向XSample的指針或者寫一個合適的拷貝構造函數。

8

因爲你有一個非平凡的析構函數(更準確地說是因爲你的類包裝了內存分配),所以你需要一個合適的拷貝構造函數和賦值操作符。見「的三巨頭規則」:


更新:

正如馬丁·約克在評論中提到的,這個答案真的只是解決的直接原因問題,但並不真正提出解決問題的最佳方法,即使用自動管理資源的RAII類成員。表面上(給出示例代碼),Beat成員可能是std::vector<>而不是指向手動分配數組的指針。一個vector<>成員將允許該班級不需要特殊的dtor,copy ctor或指派操作員 - 如果它是vector<>,則所有這些片段將自動爲Beat成員提供。

+0

或者他可以分配一個節拍向量。 – 2010-05-11 22:24:31

+0

這是一個可怕的解釋(維基鏈接)。我會說這甚至不是很好的建議。如果一個對象進行內存管理,那麼除非你正在構建一個智能指針,否則你做出了糟糕的設計決定。一個對象應該通過完成其正常工作並對其成員之一進行內存管理來完成特定任務,而實際上該任務正在嘗試執行2個任務,並且如果用戶將另一個託管對象添加到該類中,則很難得到正確的結果。最簡單的解決方案是將內存管理留給專門爲此設計的對象。 – 2010-05-11 22:38:34

+0

男人我心情不好時可能是卑鄙的。抱歉。 – 2013-03-29 14:28:35

1

發生了什麼是Samples.push_back()將其參數複製到矢量中。由於XSample沒有定義拷貝構造函數,因此編譯器會創建一個默認構造函數,它將執行淺拷貝。這意味着矢量中的原始指針和副本中的指針指向相同的內存。然後在push_back()的末尾破壞原始文件,刪除Beat指針。

在main的末尾,Dynamo被銷燬,調用每個元素的析構函數。這會嘗試刪除已刪除的指針Beat,導致您的雙重刪除錯誤。