0

我正在尝试将二维元胞自动机从处理转换为 openFrameworks (C++)。我为细胞和生命游戏功能编写了类。应用程序成功构建但立即崩溃并出现以下错误:线程 1:程序收到信号:“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() 方法的位置。任何帮助深表感谢。

4

2 回答 2

1

您在这里有一个越界访问,因为向量的大小为 0:

board[rows][cols];

您可以像这样在构造函数初始化列表中初始化向量:

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

这将初始化board为 size rows,并且它的每个元素都是 size 的向量cols。然后你可以给它的元素赋值:

cell c = ...;
board[i][j] = c;
于 2013-02-25T19:06:38.923 回答
0

由于未初始化的向量,您肯定有越界访问。从技术上讲,您的向量已初始化,但仅作为一个空容器,您暗示您应该保留足够的单元格以将其及其包含的向量视为二维数组,因此必须 a) 在循环中添加单元格 b) 使用范围构造函数 c) 使用计算元素数量的构造函数。更多信息可在此处获得。

最好始终确保您的类型在构造函数结束时可用。更喜欢在构造函数初始化列表中初始化你能做的事情,并在任何需要更多逻辑的事情上使用构造函数作用域。如果您的类型不能始终完全构造,请考虑命名构造函数 idiom。基本上,您只是从静态或非成员友元函数返回一个句柄,允许您为不成功的创建返回一个标记值(也就是指针的 N​​ULL)。

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

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

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

如果您使用 C++11,您可以使用新的内置智能指针之一,或者您可以随时回退boost

关键是您应该更喜欢使用RAII实践来避免悬空引用。尽管 C++ 没有内置的垃圾收集器,但您可以使用 RAII 原则实现令人难以置信的稳定产品。要避免的主要事情是循环引用,可以通过对不需要引用保持活动的关系使用弱引用来减轻这种引用。一个常见的例子是当你有一个对象层次结构时,父类持有对子类的引用,而子类持有对父类的引用。子级可能不需要对父级的强引用,因为当父级这样做时,他们将超出范围。

于 2013-02-25T19:24:58.967 回答