2

私は現在、プロジェクト、より正確にはタングラム ゲームに取り組んでいます。セグメンテーション違反に問題があり、その理由がわかりません。

プロジェクト全体があることを考えると、問題を単純化しようとします: 特に Menu オブジェクト (およびその他のもの) を含む GameManager クラスがありますが、それは重要ではないと思います。gameManager はこれを初期化するために使用されます。 Menu には Button のベクトルが含まれています (各ボタンには、ユーザーがクリックしたときにアクションを実行するためのラムダがあります)。

std::vector<std::unique_ptr<Button>> buttons;

それがどのように機能するかを説明するために、例を挙げます。ユーザーが「ロード」ボタンをクリックすると、gameManager はメニューに含まれる現在のボタンを削除し、そのメニューに新しいボタンを追加します。

void GameManager::initMainMenuButtons() {
...
menu -> addButton(std::unique_ptr<Button>(new Button(x1, y1, x2, y2, "Create",
    [this]{
        std::cout << "Create level" << std::endl;
        menu->clear()
        initCreateLevelButtons();
        actionManager->setMenu(menu);
    }
)));
...
}

そのコード サンプルには、"Load" や "Quit" などのいくつかのボタンを menu に追加するメソッド initMainMenuButtons があります。ユーザーが「作成」をクリックすると、インターフェイスを変更したい(ボタンの追加と削除)。したがって、ボタンを削除するには、メソッド clear() を呼び出します。

void Menu::clear() {
  buttons.clear();
  decorationPieces.clear(); // not interesting
}

unique_ptr を使用しているため、手動でボタンを削除する必要はありません。これまでのところ、問題はありません。ボタンのベクトルは空 (サイズは 0) のようです。次に、メソッド initCreateLevelButtons() が呼び出されます。このメソッドは initMainMenu と非常によく似ています: メニューにボタンを追加するだけです。この呼び出し中、ボタンはベクターに正しく追加されているように見えます。ベクターの内容を最後に出力すると、ベクターには正しいボタンが含まれています。

そして、問題が発生します。initCreateLevelButtons() の呼び出し後、メニューを使用したいときにセグメンテーション違反が発生するため、actionManager->setMenu(menu);機能しません。menu を印刷して、std::cout << menu << std::endlこのポインターが nullptr かどうかをテストしようとしましたが、どちらも機能しません。メニューが initCreateLevelButtons() の最後の行で正しいように見え、直後に無効になる理由がわかりません。ボタンのベクトルをクリアしない場合 (メニュー -> クリア命令)、プログラムは動作しますが、最後のボタンはまだここにあります)。

私は生のポインターを使用しようとしましたが、ボタンが削除されない限り、プログラムがベクトルをクリアできることに気付きました (ボタンを削除するループを追加すると、問題が発生します)。ボタンの削除。理由がわかりません、行き詰まっています。すでに述べたように、コードはプロジェクト全体の一部であるため、他のものを導入せずにクラスを導入するのは難しいため、うまく説明したかどうかはわかりません。メソッドの詳細または完全なコードが必要な場合は、提供できます。

4

2 に答える 2

5
  1. menu一部の寿命を維持しますbutton
  2. buttonの寿命を維持するlambda
  3. クリックするとbutton lambdaクリアmenu
  4. menuデストラクタ クリアbutton,buttonクリアlambda
  5. lambda実際にはすでに破棄されている場合でも実行を継続します -> 未定義の動作はクラッシュで終了します

今の質問は: あなたはButtonクラスを所有していますか?
はいの場合、それを修正する最も簡単な方法は、ボタンでラムダのコピーを呼び出すことです。

于 2020-02-17T16:58:09.600 に答える