2013-04-18 135 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后,如果您想初始化列表。