質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

std::vectorの添字がうまく機能しません

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,298

ganariya2525

score 48

前提・実現したいこと

現在C++とSiv3Dで落ち物パズルゲームを制作しています。

発生している問題・エラーメッセージ

std::vectorを使用して'Block'クラスを格納しようとしていたのですが
(std::vector<Block> bronzeと宣言)
bronze[0]などとアクセスしようとするとエラーが起きてしまいました。
発生した箇所はboard.cpp内のdropBronze関数です。

Expression: vector subscript out of range

該当のソースコード

#pragma once
#include "Block.hpp"

///<summary>
///<para>Boardクラス</para>
///<para>・Boardのサイズは大きい方</para>
///<para>・位置=画面上のもの</para>
///<para>・座標=二次元配列のこと</para>
///</summary>
class Board {

public:
    Board() = default;
    Board(WhichPlayer _whichPlayer);
    ~Board();

public:
    const Point            BOARD_VISUAL_SIZE;            //見た目上の二次元配列
    const Point            BOARD_ACTUAL_SIZE;            //実際の二次元配列
    const Point            BOARD_POINT_1P;            //1Pの画面上の位置
    const Point            BOARD_POINT_2P;            //2Pの画面上の位置
    const Point            INIT_BRONZE_COORDINATE;        //ブロンズの基準の初期座標
    const Point            BOARD_RECTANGLE_SIZE;        //ボードのサイズ
    const int            BLOCK_SIZE;
    const unsigned int        BRONZE_MAX_SIZE;
    const int            RED_NUM;
    const int            BLUE_NUM;
    const int            GREEN_NUM;
    const int            YELLOW_NUM;
    const int            PURPLE_NUM;
    const int            SELULIAN_NUM;
    const int            WALL_NUM;   
    const int            NONE_NUM;

public:
    void            init();
    void            update();
    void            draw() const;

    void            boardInit();
    void            bronzeInit();
    void            boardDraw() const;
    void            bronzeDraw() const;

    void            addBlockToBronze(Point coordinate,BlockColor blockColor);
    void            moveBronzeIndicator(int direction);
    void            dropBronze();
    void            checkBoardConnection();

    bool            isCanMoveBronze(int direction);
    bool            isCanAddBlockToBronze();
    bool            isBronzeDontCollideWithBoard(Point _coordinate);
    bool            isReachFallingDefaultCount();

private:
    std::vector<std::vector<BlockColor>>      board;
    std::vector<Block>        bronze;
    std::vector<Point>        candidates;
    Point            bronzeIndicator;
    WhichPlayer            whichPlayer;
    Point            boardVisualPoint;
    Rect            rectangle;
    int                fallingCount;
    int                fallingDefaultCount;
};


#include "Board.hpp"



Board::Board(WhichPlayer _whichPlayer) :
    whichPlayer(_whichPlayer),
    BOARD_VISUAL_SIZE(Point(7, 13)),
    BOARD_ACTUAL_SIZE(Point(9, 15)),
    BOARD_POINT_1P(150, 100),
    BOARD_POINT_2P(850, 100),
    INIT_BRONZE_COORDINATE(3,0),
    BOARD_RECTANGLE_SIZE(280,520),
    BLOCK_SIZE(40),
    BRONZE_MAX_SIZE(5),
    RED_NUM(0),
    BLUE_NUM(1),
    GREEN_NUM(2),
    YELLOW_NUM(3),
    PURPLE_NUM(4),
    SELULIAN_NUM(5),
    WALL_NUM(6),
    NONE_NUM(7)
{
    init();
}


Board::~Board() {

}

void Board::init() {
    boardInit();
    bronzeInit();
}


void Board::update() {
    if (Input::Key1.clicked) {
    dropBronze();
    }
}

void Board::draw() const {
    rectangle.draw();
    boardDraw();
    bronzeDraw();
}

void Board::boardInit() {
    board.resize(BOARD_ACTUAL_SIZE.x);
    for (int i = 0; i < BOARD_ACTUAL_SIZE.x; i++) {
    board[i].resize(BOARD_ACTUAL_SIZE.y);
    }

    for (int i = 0; i < BOARD_ACTUAL_SIZE.x; i++) {
    for (int j = 0; j < BOARD_ACTUAL_SIZE.y; j++) {
        board[i][j] = static_cast<BlockColor>(NONE_NUM);
    }
    }
    for (int i = 0; i < BOARD_ACTUAL_SIZE.x; i++) {
    board[i][0] = static_cast<BlockColor>(WALL_NUM);
    board[i][BOARD_ACTUAL_SIZE.y - 1] = static_cast<BlockColor>(WALL_NUM);
    }
    for (int i = 0; i < BOARD_ACTUAL_SIZE.y; i++) {
    board[0][i] = static_cast<BlockColor>(WALL_NUM);
    board[BOARD_ACTUAL_SIZE.x - 1][i] = static_cast<BlockColor>(WALL_NUM);
    }

    if (whichPlayer == WhichPlayer::PLAYER1) {
    boardVisualPoint = BOARD_POINT_1P;
    }
    else {
    boardVisualPoint = BOARD_POINT_2P;
    }
    rectangle = Rect(boardVisualPoint, BOARD_RECTANGLE_SIZE);
}
void Board::bronzeInit() {
    bronzeIndicator = INIT_BRONZE_COORDINATE;
    std::vector<Block>().swap(bronze);
}
void Board::bronzeDraw() const {
    for (unsigned int i = 0; i<bronze.size(); i++) {
    TextureAsset(L"Block")(BLOCK_SIZE*static_cast<int>(bronze[i].getBlockColor()), 0, BLOCK_SIZE, BLOCK_SIZE).draw(boardVisualPoint +BLOCK_SIZE*(bronzeIndicator+bronze[i].getPoint()));
    }
}
void Board::boardDraw() const {
    for (int i = 0; i < BOARD_VISUAL_SIZE.x; i++) {
    for (int j = 0; j < BOARD_VISUAL_SIZE.y; j++) {
        if (static_cast<int>(board[i + 1][j + 1]) < 5) {
        TextureAsset(L"Block")(BLOCK_SIZE*static_cast<int>(board[i + 1][j + 1]), 0, BLOCK_SIZE, BLOCK_SIZE).draw(boardVisualPoint + Point(i*BLOCK_SIZE, j*BLOCK_SIZE));
        }
    }
    }
}

void Board::addBlockToBronze(Point coordinate,BlockColor blockColor) {
    for (auto& x : bronze) {
    x.setPoint(x.getPoint() + Point(0, 1));
    }
    bronze.emplace_back(Block(blockColor,coordinate));
}

void Board::moveBronzeIndicator(int direction) {
    bronzeIndicator += Point(direction, 0);
}

void Board::dropBronze() {
    Point dropBaseCoordinate = Point(0,0);
    for (auto& x : bronze) {

    }
 //   while (board[bronzeIndicator.x+1][(dropBaseCoordinate + bronze.front().getPoint()).y + 1] == BlockColor::NONE) {
    //dropBaseCoordinate += Point(0, 1);
 //   }
    for (auto& x : bronze) {
    board[bronzeIndicator.x + 1][x.getPoint().y + dropBaseCoordinate.y + 1] = x.getBlockColor();
    }

    bronze[0];
    bronzeInit();
}

bool Board::isCanAddBlockToBronze() {
    if (bronze.size() < BRONZE_MAX_SIZE) {
    bool isCanBronzeAdd = true;
    for (auto& x : bronze) {
        if (!isBronzeDontCollideWithBoard(x.getPoint() + bronzeIndicator + Point(0, 1))) {
        isCanBronzeAdd = false;
        }
    }
    return isCanBronzeAdd;
    }
    return false;
}

bool Board::isCanMoveBronze(int direction) {
    int valid = bronzeIndicator.x + direction;
    if (valid >= 0 && valid < BOARD_VISUAL_SIZE.x) {
    bool isCanBronzeMove = true;
    for (auto& x : bronze) {
        if (!isBronzeDontCollideWithBoard(x.getPoint()+bronzeIndicator+Point(direction,0))) {
        isCanBronzeMove = false;
        }
    }
    return isCanBronzeMove;
    }
    return false;
}

bool Board::isBronzeDontCollideWithBoard(Point _coordinate) {
    if (board[_coordinate.x + 1][_coordinate.y + 1] == BlockColor::NONE) {
    return true;
    }
    else {
    return false;
    }
}

試したこと

brozneをfor文やfor auto文で回した場合エラーはありませんでした。
添字アクセスまたは、front()などでアクセスしてしまうとエラーが発生しました。

よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yohhoy

    2017/11/04 11:27 編集

    オレオレ記法ではなく https://teratail.com/help/question-tips#questionTips3-7 を参考にMarkdown形式の利用をお願いします( [Block] → `Block` のように書いてください)。また、「問題を再現」する「具体的な」ソースコードを提示ください。
    なお、エラーメッセージ自体は「blocksに要素が一つも含まれていない」ことを示唆しています。

    キャンセル

  • ganariya2525

    2017/11/04 12:01

    質問を修正させていただきました。よろしくお願いいたします。

    キャンセル

回答 1

checkベストアンサー

+1

yohhoyさんが既に指摘されているように、おそらく要素が空であることが原因です。

#include <iostream>
#include <vector>

void check(const std::vector<int>& vec) {
    std::cout << "range for" << std::endl;
    for(size_t i = 0, end_i = vec.size(); i < end_i; i++) {
        std::cout << vec[i];
    }
    std::cout << std::endl;

    std::cout << "itr for" << std::endl;
    for(auto itr = vec.cbegin(), end = vec.cend(); itr != end; itr++) {
        std::cout << *itr;
    }
    std::cout << std::endl;

    std::cout << "for each" << std::endl;
    for(const auto elem: vec) {
        std::cout << elem;
    }
    std::cout << std::endl;

    std::cout << "front\n"
              << vec.front() << std::endl;

    std::cout << "raw index\n"
              << vec[0] << std::endl;
}

int main(void) {
    check({1, 2, 3});
    check({});
    return 0;
}

実行結果

range for
123
itr for
123
for each
123
front
1
raw index
1
range for

itr for

for each

ここで落ちる

要素数も確認せずに急に添え字アクセスするのは非常に危険です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る