2014-12-08 128 views
0

我是一名學生,所以我前面道歉,不使用正確的論壇協議。我已經在這個問題上搜尋了幾個小時,我的同學們都無法提供幫助。我的任務是在C++中創建一個拷貝構造函數,重載賦值操作符(=)和析構函數('三個')來管理堆中的數組。我在VS13中寫下的內容會產生正確的輸出,但我得到一個調試錯誤:檢測到堆損壞:C++ crt檢測到應用程序在堆緩衝區結束後寫入內存 任何人都可以給我一些指導,我甚至不會知道在哪裏看。謝謝!!複製構造函數和重載賦值運算符堆損壞錯誤

//copy constructor 

myList::myList(const myList& source){ 
cout << "Invoking copy constructor." << endl; 
array_capacity = source.array_capacity; //shallow copy 
elements = source.elements; //shallow copy 
delete[] arrayPointer; 
arrayPointer = new double(source.array_capacity); //deep copy 

for (int i = 0; i < array_capacity; i++) //copy array contents 
    { 
     arrayPointer[i] = source.arrayPointer[i]; 
    } 
} 

//overloaded assignment operator 
myList& myList::operator=(const myList& source){ 

cout << "Invoking overloaded assignment." << endl; 

if (this != &source){ 

array_capacity = source.array_capacity; //shallow copy 

elements = source.elements; //shallow copy 

delete[] arrayPointer; //delete original array from heap 

arrayPointer = new double(array_capacity); //deep copy 

for (int i = 0; i < source.array_capacity; i++) {//copy array contents 
    arrayPointer[i] = source.arrayPointer[i]; 
     } 
    } 
return *this; 
} 

//destructor 
myList::~myList(){ 

cout << "Destructor invoked."<< endl; 

delete[] arrayPointer; // When done, free memory pointed to by myPointer. 

arrayPointer = NULL; // Clear myPointer to prevent using invalid memory reference. 
} 

回答

2

您的代碼有幾個問題。首先,您在arrayPointer上調用delete,但它尚未初始化爲任何內容。事實上,這可能最終會刪除已分配的內存,或導致實施delete中的例外或資產。第二次初始化時,您將分配一個初始化爲source.array_capacity的值double。注意下面一行中使用的括號。

arrayPointer = new double(source.array_capacity); 

這樣肯定會導致在複製過程中出現未定義的行爲,因爲最終訪問數組邊界之外的元素。上面一行是存在於你的拷貝構造函數和拷貝賦值運算符,應該用方括號,而不是像這樣:

arrayPointer = new double[source.array_capacity]; 

你也從來沒有檢查,看看是否有存儲在myListsource實例的任何元素。在這種情況下,您應該將nullptr(或C++ 03中的NULL)分配到arrayPointer

作爲一個附註,你並不需要在你的析構函數中指定NULLarrayPointer。一旦對象被銷燬,它就消失了,任何在事後訪問它的嘗試都會導致未定義的行爲。

+0

你的建議奏效!你是一個拯救生命的人,謝謝!我是否應該將此帖標記爲「已回答」?我怎麼做? – 2014-12-08 02:37:59

+0

是的,如果答案解決了您的問題,那麼您應該通過點擊答案左上角的複選框將其標記爲已接受。如果有多個答案有幫助,那麼由您來決定哪一個答案值得接受。如果您想給貢獻者一點紅利,您也可以提出答案。 – 2014-12-08 02:43:44

1

Captain Obvlious已經指出你的拷貝構造函數存在這個問題。

您將會注意到,複製構造函數和賦值運算符包含許多相同的代碼,但有細微的差別。事實上,這可能是你如何以錯誤結束(賦值運算符需要delete[]舊值,但複製構造函數沒有。

代碼重複是不好的,因爲它會導致像這樣的微妙錯誤蔓延你可以在這裏使用一個很好的模式是所謂的copy and swap idiom

的要點是你定義的拷貝構造函數,你還可以定義swap。那麼你得到免費的分配。這工作,因爲swap更容易實現它比賦值運算符正確,另一個主要好處是沒有任何問題可以出錯(您不必擔心內存不足錯誤等)。

在你的代碼中;讓您的固定拷貝構造函數,你可以添加類定義:

friend void swap(myList &a, myList &b) 
{ 
    std::swap(a.array_capacity, b.array_capacity); 
    std::swap(a.arrayPointer, b.arrayPointer); 
    std::swap(a.elements, b.elements); 
} 

現在賦值運算符是非常簡單的:

myList& myList::operator=(const myList &source) 
{ 
    myList temp(source); 
    swap(*this, temp); 
    return *this; 
} 

從當前對象舊的資源由析構函數刪除temp。此版本甚至不需要檢查自我分配,因爲std::swap(x, x)已定義良好。

如鏈接頁面所述,甚至可以通過按值取代source來進一步優化這一點。

相關問題