2012-04-26 9 views
4

私は単純なConnect 4ゲームを設計しています。これまでのところ、私は4つの基になるクラスを持っています:`this 'は0x0と同じで、私のプログラムがクラッシュするのはなぜですか?

Colour - 色を表すのはRGBAです。変換演算子を含みます。

Player - ゲームのプレイヤーを表します。各PlayerにはColourと名前があります。

Board - 再生ボードを表します。これには寸法と、これらの寸法を持つTileの2Dベクトルが含まれています。

Tile - ネストされたクラスBoard以内。ボード上の1つのスペースを表します。各Tileは、そのタイルの所有者にColourstd::unique_ptrを持ちます。所有者はnullptrで始まり、からPlayerに一度変更することができます。色は透明な黒色で始まります。


私はColourクラスをテストしましたが、正常に動作しているようです。私のPlayerクラスもチップトップ型です。しかし、私はBoard/Tileクラスにいくつか問題があります。

私のテストでは、2人のプレーヤーとボードを作成しました。これらは正常に実行されます。次に、各タイルに1回、ボードの寸法をループします。私はその後j、あなたはそれを印刷することを期待したい方法でiと行と列を通じて

board.tile (j, i).claimBy (p2); 

ループが行くを呼び出します。

tile (j, i)は、私が作業しているタイルを取得します。それは期待どおりに動作します。クラッシュをもたらす事象の


チェーン:

bool Board::Tile::claimBy (const Player &owner) 
{ 
    if (!_owner) 
    { 
     *_owner = owner; 
     _colour = owner.colour(); 
     return true; 
    } 

    return false; 
} 

_ownerは私std::unique_ptr<Player>次のとおりです。

claimBy (p2)次のようにそれが実装されているプレイヤー2によって主張になるためにタイルを設定します。まず、タイルの所有者が以前に設定されているかどうかを確認します(つまり、nullptrではありません)。そうでない場合は、渡されたものの内側にPlayerを設定します。次に、タイルの色を更新してtrueを返します。タイルが以前に要求されている場合は、falseを返します。

デバッガに続いて、*_owner = owner;という行でクラッシュが発生します。私は暗黙のコピーコンストラクタであることを覚えています(クラスはColour _colourstd::string _nameしか持っていないことに注意してください)(クラスの私の宣言)に私を連れて行きます。

私は再びColour::operator=につながります(コピーコンストラクタが呼び出すのが理にかなっています)。定義は次のとおりです。

Colour &Colour::operator= (const Colour &rhs) 
{ 
    if (*this != rhs) 
    { 
     _red = rhs.red(); 
     _green = rhs.green(); 
     _blue = rhs.blue(); 
     _alpha = rhs.alpha(); 
    } 

    return *this; 
} 

パスは*this != rhsに変わります。これはoperator==にちょうど逆の呼び出し、次のとおりです。

return red() == rhs.red() 
    && green() == rhs.green() 
    && blue() == rhs.blue() 
    && alpha() == rhs.alpha(); 

ここで最初の比較はred() == rhs.red()はちょうどreturn _red;あるred()を持っています。これは、プログラムがクラッシュするポイントです。デバッガには、thisthis->_red)が0x0であることが示されています。

なぜこれが起こっているのかはわかりません。私の最高の推測は、私が間違ってスマートポインタを使用しているということです。以前は実際に使用したことはありませんでしたが、普通のポインタとよく似ているはずです。ポインタがnullptrの場合、releaseは何も達成できませんでした。

thisが0x0の原因は何ですか?

編集:
私は、各コンストラクタで行うように私はどれも透明な黒ではないメンバー初期化子(例えばBoard::Tile::Tile() : _colour (Colours::NONE), _owner (nullptr){})、で、すべてが初期化されると確信しています。

私はデバッガに習熟していません。なぜなら、私はそれをデバッグ値を印刷する以上には使用していないからです。

+0

サイドノート:タイルをボードにするのは本当に意味がありますか? – Cameron

+0

@Cameronでは、is-a関係は継承に関係します。 'Tile'クラスの私の目標は、' Board'に完全に含めることでした。 'tile'関数はもともと' const'リターンでしたが、私はテストのためにそれを変更しました。タイルは「ボード」の外からアクセスできますが、新しいタイルは作成されず、作成されたばかりではありません。もちろん、「ボード」はタイルのベクトルを介して非constアクセスを持っています(私が提供する関係があります)。つまり、ボードオブジェクトにはタイルの2Dベクトルがあります。 – chris

+0

デザインに関する無関係なコメント:ボードを操作するゲームロジックは、RGBAカラーに関わる必要はありません。私は、それをコントロールするプレイヤーを参照するだけで、どのプレイヤーに基づいて色を選択させるかを描画コードに任せます。 – Wyzard

答えて

3

ライン

*_owner = owner; 

ownerオブジェクトのコピーを作成し、_ownerポイントにその場所で保管してください。」という意味問題は_ownerがまだ何も指していないことです。それはまだヌルです。

あなたが本当にそのプレイヤーがコントロールする各タイルにPlayerオブジェクトのコピーを作りたい場合は、あなたが

_owner.reset(new Player(owner)); 

を行う必要がある。しかしPlayerオブジェクトのコピーを作成することは奇妙なことであると思いますする。代わりにshared_ptrを使用することを検討してください。owner_ownerの両方をshared_ptrとすることができ、通常の方法でもう一方に割り当てることができます。

+0

私はそれを見ていきます、ありがとう。引数は実際の 'Player'であると思っていますが、' nullptr'か 'Player'のどちらかしかないので、' unique_ptr'と思っていました。私は間違っていると思う。 – chris

+0

'unique_ptr'の「ユニーク」は、いったん' Player'を指すと、別のものを指し示すことはできません。これは、 'Player'を指し示すとき、* else *が同じ' Player'を指していると約束しているので、 'unique_ptr'が有効範囲外になったときに' Player'を削除しても安全です。 'shared_ptr'は、同じ' Player '(例えば、プレーヤーがコントロールする各タイルに1つ)への複数のポインタを持ち、それらのポインタがすべてスコープから外れるまで、 'Player'は削除されません。 – Wyzard

+0

'reset'はトリックをしたようです:)私はそれについて考えましたが、実際は各プレーヤーが初期化されていて、それ以降は変更がありません。次のレイヤーはターン、勝利などを処理する "インターフェース"です。この動作のために、コピーを作成してプレイヤーの色を読み取るだけで保存することができますそれは所有されています。私はスマートポインタについて読んだので、その違いを知っていますが、その決定の背後にある私の論理には欠陥があると思います。 – chris

1

デフォルトで初期化されたstd::unique_ptr<Player>で始まります。つまり、いくつかのクリーンアップセマンティクスを持つNULLポインタに相当します。次に、ステートメント*_owner=owner;で逆参照して、それに割り当てることができます。

したがって、*_owner=owner;というステートメントは、暗黙の代入演算子を呼び出すことによって、基本的に((Player*)NULL)->operator=(owner);に相当します。これが最初に行うことは((Player*)NULL)->_colour=owner._colour;に相当します。見つけ出すthis==NULLはここでは驚くべきことではありません。確かに、それは期待されています。

修正は、実際に何が起こりたいかによって異なります。それぞれBoard::Tileには、ownerという全く新しいコピーが必要ですか?次に、代わりに_owner.reset(new Player(owner))としたいとします。各タイルに既存のプレーヤーの参照を保持させたいだけですか? PlayerオブジェクトownerがBoard :: Tileオブジェクトよりも長く存続することを保証できますか?次に、生のポインタが必要です。(Board :: Tileの宣言で)Player const *_owner;(実装中)_owner=&owner;

関連する問題