2013-01-22 46 views
1

我將問題縮小到將2個對象(包含指針數據成員)傳遞給一個簡單的void函數。該函數返回乾淨,但當main()嘗試退出時,它不能回收2個對象中的第一個。下面是一段代碼示例,它顯示了這個問題 - 以及打印語句,以顯示對象在構建,傳遞和銷燬時的地址。無法退出,因爲析構函數錯誤導致執行main()在退出時暫停

如果我只打電話給「print1」 - 程序運行良好。但是,如果我調用「printboth」 - 那麼不能釋放對象「myNumbers」。我也可以通過刪除析構語句使錯誤消失:

delete [] number; 

但我不認爲這是一個好主意。

任何人有任何想法?

class dummy 
{ 
public: 
    dummy() { 
     number = new int[1]; 
     currentPos = -1; 
     std::cout<<"default constructor called for "<<this<<std::endl; 

    } 
    dummy(int len) { 
     number = new int[len]; 
     currentPos = -1; 
     std::cout<<"parameterized constructor called for "<<this<<std::endl; 

    } 
    ~dummy() { 
     cout<<"Calling destructor for "<<this<<endl; 
     delete [] number; 
    } 
    int getNextNumber() { 
     currentPos++; 
     return number[currentPos]; 
    } 
    void setNumbers(int position, int value) { 
     number[position] = value; 
    } 
private: 
    int* number; 
    int currentPos; 
}; 

void print1(dummy); 
void printboth(dummy, dummy); 

int main() { 
dummy myNumbers(3); 
myNumbers.setNumbers(0,0); 
myNumbers.setNumbers(1,1); 


dummy myOtherNumbers(3); 
myOtherNumbers.setNumbers(0,4); 
myOtherNumbers.setNumbers(1,5); 

cout<<"Address of myNumbers is  "<<&myNumbers<<endl; 
cout<<"Address of myOtherNumbers is "<<&myOtherNumbers<<endl; 

print1(myNumbers); 
printboth(myNumbers, myOtherNumbers); 

system("PAUSE"); 
return 0; 
} 

void print1(dummy num) { 
cout<<"Address of num is  "<<&num<<endl; 
for (int i=0;i<4;i++) 
    cout<<"Dummy number1 is "<<num.getNextNumber()<<endl; 
return; 
} 
void printboth(dummy num1, dummy num2) { 
cout<<"Address of num1 is  "<<&num1<<endl; 
cout<<"Address of num2 is  "<<&num2<<endl; 
for (int i=0;i<4;i++) { 
    cout<<"Dummy number1 is "<<num1.getNextNumber()<<endl; 
    cout<<"Dummy number2 is "<<num2.getNextNumber()<<endl; 
    } 
return; 
} 
+3

你的類不遵循三個規則。使用RAII。 – chris

+0

@chris,將三人和RAII的規則解釋給明確學習的人是有幫助的...... –

+0

好吧,答案有RoT鏈接。這是RAII之一:http://dl.dropbox.com/u/6101039/Modern%20C++.pdf – chris

回答

2

你沒有按照rule of three

的問題是,當你調用PRINT1或printboth編譯器調用默認的拷貝構造函數(因爲你沒有提供一個)。該複製構造函數將副本的number成員變量設置爲與原始值相同的值。當在副本上調用析構函數時,內存被釋放。你的原始對象現在指向已被釋放的內存,所以當它的析構函數被調用時,你會崩潰(Nik Bougalis)。

void print1(dummy); 
void printboth(dummy, dummy); 

您可以通過const引用傳遞假以避免不必要的副本,但強烈建議您遵循rule of three

void print1(const dummy&); 
void printboth(const dummy&, const dummy&); 

注: 您不僅創造size =1陣列,它是沒有必要的,只要使用int number;作爲會員。如果數字保存動態分配的數組,請嘗試使用std::vector<int>

getNextNumber存在缺陷,當它被多次調用時,number[currentPos];訪問邊界數量超出未定義的行爲。

int getNextNumber() { 
     currentPos++; 
     return number[currentPos]; 
    } 

這意味着什麼建議:

int getNextNumber() const { 
     return number[currentPos]; 
    } 
+1

您應該更詳細地解釋一下:問題在於,當您調用'print1'或'printboth'時,編譯器會調用默認的複製構造函數(因爲您沒有提供它)。該拷貝構造函數將拷貝的'number'成員變量設置爲與原始*相同的*值。當在副本上調用析構函數時,內存被釋放。你的*原始*對象現在指向已經被釋放的內存,所以當它的析構函數被調用時,你會崩潰。你可以在這裏閱讀關於三規則的更多信息:http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three –

+0

Nik,你應該作爲回答發佈,現在我偷了你的更新我的答案。 – billz

+0

這些迴應肯定有幫助。我現在需要澄清我正在進行的任務。函數原型給了我(它沒有使用call-by-reference),我不能使用「const」,因爲在打印函數中我稱之爲「getNext」 - 它更新了一個成員變量currentPos。我將需要詢問是否允許我通過添加複製構造函數和複製賦值運算符來添加到原始代碼(已提供)。 –