0

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() メソッドを呼び出す場所に表示されます。どんな助けでも大歓迎です。

4

2 に答える 2

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;
于 2013-02-25T19:06:38.923 に答える
0

初期化されていないベクトルのため、間違いなく範囲外のアクセスがあります。技術的には、ベクトルは初期化されますが、空のコンテナーとしてのみ、それとそれに含まれるベクトルを 2d 配列として処理するのに十分なセルを予約する必要があることを暗示しているため、a) ループにセルを追加する b) 範囲を使用する必要がありますコンストラクター c) 要素数をカウントするコンストラクターを使用します。詳細については、こちらをご覧ください

コンストラクターの最後まで型が使用可能であることを常に確認することをお勧めします。コンストラクターの初期化リストでできることを初期化することを好み、より多くのロジックを必要とするものにはコンストラクター スコープを使用することにフォールバックします。型を完全に構築できない場合は、名前付きコンストラクタのイディオムを検討してください。基本的に、静的または非メンバーのフレンド関数からハンドルを返すだけで、作成に失敗した場合にセンチネル値 (ポインターの場合は NULL) を返すことができます。

C++ 型システムがどのように機能するかについても考慮する必要があるようです。

型「セル」が何らかのデータ型または単にPOD型へのハンドルでない限り、セル オブジェクトのコピーではなく、ヒープ割り当てオブジェクトへの参照をベクターに保存することをお勧めします。

セルをポリモーフィック型のように扱う必要がある場合 (基本クラスとして使用したい場合)、ポインターまたはスマート ポインターなどの何らかの形式のハンドルをベクターに格納する必要があります。

C++11 を使用している場合は、新しく組み込まれたスマート ポインターのいずれかを使用するか、常にboostにフォールバックできます。

重要な点は、ダングリング参照を回避するためにRAIIプラクティスを使用することを優先する必要があるということです。C++ にはガベージ コレクターが組み込まれていませんが、RAII の原則を採用することで、非常に安定した製品を実現できます。主に避けるべきことは循環参照です。これは、参照先が存続する必要のないリレーションへの弱い参照を使用することで軽減できます。この一般的な例は、親への参照を保持するインターンが子への参照を保持する親クラスがあるオブジェクト階層がある場合です。子は、親が範囲外になると範囲外になることが予想されるため、親への強い参照を必要としない可能性があります。

于 2013-02-25T19:24:58.967 に答える