C ++新手,“EXC_BAD_ACCESS”错误我不明白

时间:2013-02-25 19:03:24

标签: c++ xcode openframeworks cellular-automata

我正在尝试将2维细胞自动机从Processing转换为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()方法的位置。非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

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

board[rows][cols];

您可以在构造函数初始化列表中初始化向量,如下所示:

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

这会将board初始化为大小rows,其每个元素都是大小为cols的向量。然后,您可以为其元素指定值:

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

答案 1 :(得分:0)

由于你的未初始化的向量,你肯定有一个超出界限的访问权限。从技术上讲,你的向量是初始化的,但只是作为一个空容器,你暗示你应该保留足够的单元格来处理它及其包含的向量作为2d数组,因此必须a)在循环中添加单元格b)使用范围构造函数c)使用构造函数来计算元素的数量。有关详细信息,请here

最好始终确保构造函数末尾的类型可用。希望初始化构造函数初始化列表中的内容,然后使用构造函数作用域来处理需要更多逻辑的任何内容。如果您的类型无法始终完全构建,请考虑named constructor idiom。基本上你只是从静态或非成员友元函数返回一个句柄,允许你为不成功的创建返回一个sentinel值(对于指针也是NULL)。

听起来您需要考虑C ++类型系统的工作原理。

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

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

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

关键是你应该更喜欢使用RAII做法来避免悬挂引用。虽然C ++没有内置垃圾收集器,但您可以使用RAII原则实现非常稳定的产品。要避免的主要内容是循环引用,可以通过使用对关系的弱引用来减轻这些引用,而不需要指示对象保持活动状态。一个常见的例子是当你有一个对象层次结构时,父类持有对实习生持有对父项的引用的子项的引用。孩子们可能不需要对父母的强烈引用,因为在父母的情况下他们将被超出范围。