2013-04-18 146 views
0

我正在編寫一個程序來顯示康威的C++生命遊戲。我的教授給了我們一個描述「宇宙」的主要功能和類別,我們必須實現課堂上原型的功能。我現在的問題實際上是讓構造函數運行。我將發佈該類,然後是我爲構造函數編寫的內容。使用GDB,當我到達使用構造函數的第一行時(universe(width,height,wrap);)我得到以下錯誤:libC++ abi.dylib:terminate調用拋出異常構造函數不工作

編程接收信號SIGABRT,中止。 0x00007fff876fad46 in __kill()

任何幫助表示讚賞!下面的代碼。

// Conways game of life 

    class universe {    
private: 
int* array;  // A pointer to a [width]X[height] array of cells that constitutes  the universe 
       // for the game of life. A value of 1 signifies a live cell at that location. 
int width;  // The width of the universe. 
int height;  // The height of the universe 
int wrap;  // wrap = 1 means the universe wraps around on itself -- the right hand 
       // side connects to the left and the top connects to the bottom. 
       // wrap = 0 means the universe ends at the array boundaries. 
public: 
universe();   // A null constructor: sets array, width, height, and wrap to 0. 
universe(int,int,int); // Constructor to allocate space for a universe of given width (first value) 
        // height (second value) and wrap setting (third value). Sets all cells to 0. 
void display();  // Display the live cells in a graphics window. 
void setup();  // Display the universe then allow the user to interactively modify 
        // the cell arrangement using the mouse. 
void operator<<(char*); // Read in a universe from a file; first number has the width, 
          // second number is the height, 
          // third number is the wrap parameter, 
          // then 1s/0s in a 2D integer array represent living/dead cells. 
void operator>>(char*); // Save the universe to a file with the specified name (format as above). 
void operator=(universe); // Copy the contents of one universe to another. 
void operator<<(universe); // Calculate the new generation by applying the rules, then 
          // display the new generation. 
int neighbors(int,int);  // Returns the number of neighbors of the cell at i,j. 
int value(int,int);  // Returns the value at cell i,j (0 or 1). 
void setvalue(int,int,int); // Sets the value of the cell at i,j. 
void free(); // Release the memory used to store the universe. Set array = 0. 
}; 

// Implementation 


universe::universe(){ 
array =0;    
width = 0; 
height = 0; 
wrap = 0; 
} 

universe::universe(int width1,int height1,int wrap1){ 

int i=0, j=0; 
int* array = new int[width*height-1];  
for(i=0;i<width;i++){ 
    for(j=0;j<height;j++){ 
     array[j*width+i] =0; 
         } 
        } 
width = width1; 
height =height1; 
wrap = wrap1; 
} 
+0

你錯過了一個拷貝構造函數和一個析構函數('free()'函數不會**)。另外,我會建議一個容器,但我敢打賭你不能使用它。 – chris 2013-04-18 02:11:23

+1

你是否看到3-param構造函數在它們被實際分配之前分配一個本地數組(並且從不分配它,因此泄漏它)你的**成員**'width'和'height' * *當這個ctor完成時,你有'array'的不確定值,未定義大小的內存泄漏,以及分配的寬度+高度值。 – WhozCraig 2013-04-18 02:13:09

+0

您應該閱讀關於C++的一些文章/書籍。這段代碼就像C和C++的一些怪誕的愛情小孩。 RAII,容器和初始化列表是你的朋友。 – 2013-04-18 02:14:54

回答

1

有這麼多問題與原來的代碼是很難只是背出的名單,但我可以嘗試:

  1. 成員widthheight用於成員分配的大小,他們甚至包含前確定的價值。因此它們的使用價值是不確定的,因此內存分配表現爲未定義的行爲

  2. 分配被存儲到本地指針,然後在退出構造函數後立即丟失。它從未被分配到成員變量array。因此你正在泄漏記憶。此外,由於array(該成員)從未被分配,因此即使在構建之後其值也是不確定的,因此使用它所包含的地址進行的任何訪問(讀取或寫入)是未定義的行爲

  3. 您沒有類析構函數來清理構造函數或成員函數中分配的內存。 (假設你正確地修復了3參數構造函數,並且它實際上array成員中保存了內存分配指針)。因此,這會在銷燬時泄漏內存(假設3參數構造函數是固定的),或者在構造上(假設3參數構造函數不固定)。

  4. 你是widthheight成員目前可以接受負值,這對實際使用沒有意義,並會對您的分配造成潛在的破壞。所有成員不打算明確允許負值應該是無符號類型,size_t是常見的。

  5. 構造函數都沒有初始化列表。他們都應該。

  6. class universe爲本地成員變量動態分配內存。如果不建立虛擬析構函數,複製構造函數和賦值運算符,將提供編譯器默認實現,並且它們將最可靠地導致內存泄漏或內存損壞。此代碼應該練習The Rule of Three,目前沒有。

  7. 3-param構造函數中的當前分配大小邏輯關閉了一個元素。 (-1)不屬於那裏,緊接着的循環將寫入一個超出分配大小的元素。這是未定義的行爲

  8. 您正在使用標準庫定義的類的名稱作爲本地定義的變量/類/成員的名稱。雖然不是正式的「錯誤」,但是高度建議你避免這種做法。

強烈奉勸solid C/C++ book

+0

這是一篇很棒的文章! – Patashu 2013-04-18 02:39:39

+0

非常感謝!我意識到我用C++有很長的路要走,這個任務令人沮喪(我們不允許編輯Universe類或主函數)。在發佈了我已修復的問題1,2和4後,我意識到了這一點。我正在通過3,5,6和8(閱讀一些文獻)工作,但我確信我對於7是正確的。我將分配一個1D數組,其中包含一個索引,用於假設[寬度]中的每個數據點。 [高度]網格。如果寬度爲5,高度爲10寬度*高度= 50,但是要創建50個索引,我想分配一個大小爲49的索引。 – ConnorDurkin 2013-04-18 17:41:05

+0

關於樣本大小(5x10),**需要50個節點(5 * 10)。 **他們被*訪問*使用索引0..49,但你仍然想要50.不要混淆節點數和用於訪問它們的最大索引。前者總是比後者多一倍。如果你想要一個5x10的矩陣,你需要50個節點,**不是** 49。我希望這是有道理的。 – WhozCraig 2013-04-18 18:36:53

2
int* array = new int[width*height-1]; 

應該

array = new int[width*height-1]; 

因爲array是你的類的成員,你不應該再次聲明具有相同名稱的局部變量。否則,您不會初始化班級成員array。局部變量將隱藏類成員。

同時,您應先將值分配給widthheight,然後再與new一起使用。

你的代碼看起來應該像下面這樣:

universe::universe(int width1,int height1,int wrap1){ 
    width = width1; 
    height =height1; 
    wrap = wrap1; 
    array = new int[width*height-1];  
    for(int i=0; i<width; i++){ 
     for(int j=0; j<height; j++){ 
     array[j*width+i] =0; 
     } 
    } 
} 

更好地把成員int*arraywrap後,如果您想初始化列表。