2013-02-25 129 views
0

我试图将2维元胞自动机从处理转换为openFrameworks(C++)。我已经为单元格和生命游戏功能编写了类。应用程序生成成功,但立即崩溃并出现以下错误:线程1:编程接收到的信号:“EXC_BAD_ACCESS”。C++新手,“EXC_BAD_ACCESS”错误我不明白

这里是我的我的生活类

#include "Cell.h" 

class GoL { 

public: 
    GoL(); 
    void init(); 
    void generate(); 
    void display(); 
    void run(); 

    int w = 20; 
    int cols; 
    int rows; 

    std::vector<vector<cell> > board; 


}; 

这里的游戏标题内实现:

#include "GoL.h" 

GoL::GoL() { 
    cols = ofGetWidth()/w; 
    rows = ofGetHeight()/w; 
    board[rows][cols]; 
    init(); 
} 

void GoL::run() { 
    generate(); 
    display(); 
} 

void GoL::init() { 
    for (int i = 0; i < cols; i ++) { 
     for (int j = 0; j < rows; j ++) { 
      board[i][j] = *new cell(i * w, j * w, w); 
     } 
    } 
} 

void GoL::generate() { 
    for (int i = 0; i < cols; i ++) { 
     for (int j = 0; j < rows; j ++) { 
      board[i][j].savePrevious(); 
     } 
    } 
    for (int x = 0; x < cols; x ++) { 
     for (int y = 0; y < cols; y ++) { 
      int neighbours = 0; 
      for (int i = -1; i <= 1; i ++) { 
       for (int j = -1; j <= 1; j ++) { 
        neighbours += board[(x + i + cols) % cols][(y + j + rows) % rows].previous; 
       } 
      } 
      neighbours -= board[x][y].previous; 
      // Rules of Life 
      if  ((board[x][y].state == 1) && (neighbours < 2)) board[x][y].newState(0); 
      else if ((board[x][y].state == 1) && (neighbours > 3)) board[x][y].newState(0); 
      else if ((board[x][y].state == 0) && (neighbours == 3)) board[x][y].newState(1);   
     } 
    } 
} 

void GoL::display() { 
    for (int i = 0; i < cols; i ++) { 
     for (int j = 0; j < rows; j ++) { 
      board[i][j].display(); 
     } 
    } 
} 

错误在vector.h文件显示出来,在GoL的头文件以及我在GoL实现中调用init()方法的地方。任何帮助深表感谢。

+0

你没有在你的构造函数中正确初始化你的电路板矢量。你不需要用'new'来初始化每个单元格。改为使用临时和复制结构。 – jxh 2013-02-25 19:05:45

+0

'board [rows] [cols];'你在那里意味着什么? – 2013-02-25 19:06:35

+0

这种类型的问题只有一个很好的答案 - 使用调试器。 – 2013-02-25 19:41:27

回答

1

你有一个出界访问这里,这是因为矢量大小为0:

GoL::GoL() : cols(ofGetWidth()/w), rows(ofGetHeight()/w), board(rows, std::vector<cell>(cols)) 
{ 
} 

这将初始化:

board[rows][cols]; 

您可以在构造函数初始化列表这样的初始化向量board大小为rows,其每个元素将是大小为cols的矢量。然后你就可以将值分配给它的元素:

cell c = ...; 
board[i][j] = c; 
0

你肯定有一个越界访问,由于您未初始化向量。从技术上讲,你的矢量是初始化的,但只是作为一个空容器,你暗示你应该保留足够的单元格来把它和它包含的矢量作为二维数组,因此必须a)在循环中添加单元格b)使用范围构造函数c)使用构造函数来计算元素的数量。更多信息请见here

最好始终确保类型在构造函数的末尾可用。倾向于在构造函数初始化列表中初始化您可以做的事情,并回头使用构造函数作用域来处理需要更多逻辑的任何事情。如果您的类型不能始终构建完整考虑named constructor idiom。基本上你只是从一个静态或非成员的朋友函数返回一个句柄,允许你为不成功的创建返回一个标记值(指针为NULL)。

听起来好像你需要考虑C++类型系统是如何工作的。

除非您的类型“单元格”是某种数据类型的句柄或者只是一个POD类型,否则您可能希望在引导程序中存储对堆分配对象的引用,而不是单元对象的副本。

如果单元格必须被视为多态类型(您想将它用作基类),则需要在向量中存储某种形式的句柄,例如指针或更好的智能指针。

如果您使用C++ 11,您可以使用新的built in smart pointers之一,或者您始终可以回退boost

关键是你应该更喜欢使用RAII的做法,以避免悬而未决的参考。尽管C++没有内置的垃圾回收器,但您可以使用RAII原则获得令人难以置信的稳定产品。要避免的主要问题是循环引用,可以通过对关系进行弱引用来缓解循环引用,因为这些引用不需要引用就可以保持活跃。这是一个常见的例子,当你有一个对象层次结构,其中一个父类拥有一个引用实际持有对父对象的引用的子对象。孩子们可能不需要强烈的参考父母,因为他们预计在家长的时候会超出范围。