[VC++/DxLib]アクセス違反

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
moba
記事: 82
登録日時: 8年前

[VC++/DxLib]アクセス違反

#1

投稿記事 by moba » 8年前

こんばんは。
VisualC++(2010Express)/DxLibでゲームを作りたい素人です。お世話になります。
今回はアクセス違反が起きてしまい、原因がまるで分からないので見ていただけませんか。

余計な部分が多々あるので、3つ目のコードmap.cppの59行目、MapData::LoadMapまで飛ばして読んでください。
翌日の追記:実行すると、そこの//エラーと書いている部分でブレークします

投稿直後の追記:同じ構造のつもりで1から書きなおすと、エラーが出なかったためこの形にさせていただきました。

コード:

//main.cpp
#include "DxLib.h"
#include "map.h"

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	ChangeWindowMode(TRUE),DxLib_Init();

	MapData::LoadMap("Picture/BasePipo.png");//呼び出し先でエラー
	//入力待ち
	while( CheckHitKeyAll() == 0 )
	{
		if( ProcessMessage() == -1 )
		{
			break;
		}
	}
	DxLib_End();
	return 0;
}

コード:

//map.h
#ifndef MAP_H //二重include防止
#define MAP_H

class MapBase
{//インタフェースクラス
public:
	virtual void DrawMap() = 0;
	virtual void ScrollUpdate() = 0;
	virtual void SetThisLayer(char*,int) = 0;
	virtual void FreeThisLayer() = 0;
	virtual void ToScreen(int,int,int*,int*,int=1) = 0;
	virtual void ToCell(int,int,int*,int*) = 0;//【警告】絶対位置を引数に取る

	virtual bool IsPassable(int,int) = 0;//このレイヤのマスが通行可能か
	virtual void SetCell_chipID(int,int,int) = 0;
	virtual ~MapBase() = 0 {}
};

//マップ定義、全レイヤで共通
namespace MapData
{
	//宣言のみ【警告】定義はcpp
	extern int allLayerNum;
	extern MapBase *layer;
	//マップ定義用
	void LoadMap(char*);
	void DeleteMap();
	void GetScroll(int *x,int *y);
	void SetScroll(int x, int y);
	void GetMapSize(int *width, int *height);
	bool IsInsideMap(int x, int y);
	bool IsPassable(int x,int y);
}

struct Layer
{
	int chipID;
};
class MapBase_2 : public MapBase
{
protected:
	int thisLayerNum;
	Layer *thisLayer;//コンストラクタ内で動的に確保する
public:
	void SetThisLayer(char*,int);
	void FreeThisLayer();
	//インタフェイス系の定義
	int GetCell_chipID(int x, int y);
	void SetCell_chipID(int x,int y,int chipID);
	bool IsPassable(int x,int y);
};

class DMap : public MapBase_2
{
public:
//オーバーライド
	void DrawMap();
	void ScrollUpdate();
	void ToScreen(int,int,int*,int*,int=1);
	void ToCell(int screenX,int screenY,int *cellX,int *cellY);//絶対位置を引数に取る
};

class QMap : public MapBase_2
{
private:
public:
	//オーバーライド
	void DrawMap();
	void ScrollUpdate();
	void ToScreen(int,int,int*,int*,int=1);
	void ToCell(int screenX,int screenY,int *cellX,int *cellY);//絶対位置を引数に取る
};

#endif //MAP_H

コード:

//map.cpp
#include "map.h"
#include <DxLib.h>

using namespace MapData;

namespace MapData
{
	//定義
	MapBase *layer;
	//一時情報
	int scrollX,scrollY;
	//map
	char *mapFile;
	int mapWidth,mapHeight;
	int allLayerNum;
	int mapShiftX,mapShiftY;
	//cell
	int cellWidth,cellHeight;
	//tile
	char *tileGraph;
	int tileWidth,tileHeight;//ピクセル
	int *tileDiv;
	//QMap用
	int qCellWidth,qCellHeight;
	int leftBlank,rightBlank,upBlank,downBlank;
	int minScrollX,minScrollY;
	int maxScrollX,maxScrollY;

	void DeleteMap()
	{
		delete []layer;
	}
	void GetScroll(int *x,int *y)
	{
		*x = scrollX; *y = scrollY;
	}
	void SetScroll(int x, int y)
	{
		scrollX = x; scrollY = y;
	}
	void GetMapSize(int *width, int *height)
	{
		*width = mapWidth; *height = mapHeight;
	}
	bool IsInsideMap(int x, int y)
	{
		if(x >= 0 && x < mapWidth &&
			y >= 0 && y < mapWidth    )
		{
			return(TRUE);
		}else
		{
			return(FALSE);
		}
	}	bool IsPassable(int x,int y){return(TRUE);}
}

void MapData::LoadMap(char* file)
{
	//map
	mapFile = file;
	allLayerNum = 3;
	layer = new QMap[allLayerNum];
	for(int i = 0; i < allLayerNum; i++)
	{
		layer[i].SetThisLayer("Picture/testmap1.txt",i);//エラー!
	}
}


void MapBase_2::SetThisLayer(char *file,int a){}
void MapBase_2::FreeThisLayer(){}
int MapBase_2::GetCell_chipID(int x, int y)
{
	if( IsInsideMap(x,y) == 1 )
	{
		return( thisLayer[x + y*mapWidth].chipID );
	}else
	{
		return(-1);
	}
}
void MapBase_2::SetCell_chipID(int x,int y,int chipID){}
bool MapBase_2::IsPassable(int x,int y){return(TRUE);}

//DMap
void DMap::DrawMap(){}
void DMap::ScrollUpdate(){}
void DMap::ToScreen(int cellX, int cellY,int *screenX, int *screenY, int returnType){}
void DMap::ToCell(int screenX,int screenY,int *cellX,int *cellY){}

//QMap
void QMap::DrawMap(){}
void QMap::ScrollUpdate(){}
void QMap::ToScreen(int cellX,int cellY,int *screenX,int *screenY,int returnType){}
void QMap::ToCell(int screenX,int screenY,int *cellX,int *cellY){}
最後に編集したユーザー moba on 2016年1月05日(火) 11:18 [ 編集 1 回目 ]

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: [VC++/DxLib]アクセス違反

#2

投稿記事 by softya(ソフト屋) » 8年前

よくあるミスなので、デバッグ方法を説明します。
デバッグで開始すれば、アクセス違反でブレークするはずです。
ここで、どの行が問題なのかが分かります。
大抵は配列の添字が範囲外ですが、ポインタのミスの可能性もあります。

疑うべきは、自分の書いたコードの正しさです。
ガードしているようですが、ガードがちゃんと動作しているか確認していなかったのが今回の敗因ですね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

moba
記事: 82
登録日時: 8年前

Re: [VC++/DxLib]アクセス違反

#3

投稿記事 by moba » 8年前

> softyaさん

本当にいつもありがとうございます。
いただいたコメントからでは何が間違っているのか分かりませんでした。
考えろ自分…うーん、何を…or2

上記コードのコメント文にある通り、ブレークしたのはmap.cppの67行目です。

ガードとは、インクルードガードのことでしょうか。
一応#progma onceも使ってみたのですがダメでした。

添え字が1になるとブレークするようで、お手上げです…

layer = new QMap[3];
for(int i = 0; i < 2; i++)
{
layer.SetThisLayer("Picture/testmap1.txt",i);//エラー!
}//例えばコレでエラー

さすがにこれで要素数が3の配列になっていないわけがないと思うのですが…
なぜかウォッチ機能も使えません

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: [VC++/DxLib]アクセス違反

#4

投稿記事 by softya(ソフト屋) » 8年前

失礼。私が問題があると判断した部分まで到達していないんですね。
「エラー」と書いてある事に全く気づきませんでした。
で、今回の問題はnewでクラス配列を使用する場合に書き方が正しくないことが原因じゃないかと思います。
new クラス配列 C++ 継承で調べてみましょう。
親クラスで子クラスを配列参照するとやばいです。
ポリモーフィズムはポインタで使いましょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

moba
記事: 82
登録日時: 8年前

Re: [VC++/DxLib]アクセス違反

#5

投稿記事 by moba » 8年前

> 失礼。私が問題があると判断した部分まで到達していないんですね。
> 「エラー」と書いてある事に全く気づきませんでした。

すみません、僕の書き方が悪かったです。
追記して分かりやすくします。

> で、今回の問題はnewでクラス配列を使用する場合に書き方が正しくないことが原因じゃないかと思います。
> new クラス配列 C++ 継承で調べてみましょう。

ほとんどこちらのページしかヒットさせられませんでした。
https://yukki99.wordpress.com/2008/06/1 ... %E6%80%A7/
多態性を使うときは、
DerivedClass* p = new Class[n];
の形は使えない、と書いてあるのでしょうか。

その形を避けて2通りでやってみました。

コード:

//allLayerNum = 3をマジックナンバで書く(とりあえず)
MapBase *layer[3];//あらかじめ全レイヤ数で宣言・定義しておく

//パターンA
for(int i = 0; i < 3; i++)
{
	layer[i] = new QMap;
	layer[i]->SetThisLayer("Picture/testmap1.txt",i);
}

//パターンB
MapBase *layer[3] = {new QMap,new QMap,new QMap};
for(int i = 0; i < 3; i++)
{
	layer[i]->SetThisLayer("Picture/testmap1.txt",i);
}
ここで質問なのですが、

・やはりdeleteは各要素ごとに行わなければならないのでしょうか
 (多態性を使っているとはいえ全て同じ派生型のオブジェクトが入っていますが)
・やはりlayerの要素の数は動的に決められないのでしょうか

とりあえず動くようになったので、すっかり僕はリア充です。


> 親クラスで子クラスを配列参照するとやばいです。
→ QMapではMapBaseを配列参照? していないつもりなので、
→ どこがやばいか分かりませんでした。

> ポリモーフィズムはポインタで使いましょう。
→ MapBase *layer を使っていましたが、
→ layer.(関数名)とドット演算子を使わされていたと言うことは
→ 何か間違いがあったのでしょうか。
→ (間違ったnewの使い方をしていたので、不毛な話だったらスルーしてください)

YuO
記事: 947
登録日時: 13年前
住所: 東京都世田谷区

Re: [VC++/DxLib]アクセス違反

#6

投稿記事 by YuO » 8年前

moba さんが書きました:多態性を使うときは、
DerivedClass* p = new Class[n];
の形は使えない、と書いてあるのでしょうか。
そういうことです。
  • ポインタを動的に生成したオブジェクトを参照するために利用する
    →ポインタは「単体のオブジェクトの参照」のために利用する。ポインタの静的型とインスタンスの動的型は等しいか異なる (異なる場合は次項も含めた利用方法)。
  • ポインタを多態のために利用する
    →ポインタは「単体のオブジェクトの参照」のために利用する。ポインタの静的型とインスタンスの動的型は等しいか異なる (静的型が純粋仮想であれば必ず異なる)。
  • ポインタを配列アクセスのために利用する
    →ポインタは「配列アクセス」と「該当箇所のオブジェクトの参照」のために利用する。ポインタの静的型とインスタンスの動的型は等しい。
moba さんが書きました:・やはりdeleteは各要素ごとに行わなければならないのでしょうか
 (多態性を使っているとはいえ全て同じ派生型のオブジェクトが入っていますが)
newと同等の回数だけ行う必要があります。
ただし,通常はスマートポインタを利用するでしょうから,deleteを書く必要はありませんが。
色々とスマートポインタはありますが,とりあえずstd::unique_ptr使っておくとよいでしょう。
moba さんが書きました:・やはりlayerの要素の数は動的に決められないのでしょうか
普通にポインタのポインタを使えば可能です。
最初に「配列アクセスのため」に使い,その次に「多態のため」に使います。
まぁ,これもstd::vectorとか使うでしょうから,T **という形を使って書く必要がないですが。

moba
記事: 82
登録日時: 8年前

Re: [VC++/DxLib]アクセス違反

#7

投稿記事 by moba » 8年前

> YuOさん

まとめてくださってありがとうございます。
この辺になると、分厚めの入門書にも載っていませんね。
検索しても断片的な知識しかヒットさせられなかったため助かります。
しばしば読み返すと思います。

今回はMapBase *layer[3]と静的に確保することにします。
スマートポインタは、名前すらも知らなかったのですが、いつかお世話になりそうですね。

>softyaさん

ガードはpublic、protected、privateのことだったでしょうか。
まだそのミスに気付けていません。
よかったらもう少しヒントをいただけませんか。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: [VC++/DxLib]アクセス違反

#8

投稿記事 by softya(ソフト屋) » 8年前

IsInsideMapがバグってますよって話だけですよ。
この関数は添字外参照のガードですよね?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

moba
記事: 82
登録日時: 8年前

Re: [VC++/DxLib]アクセス違反

#9

投稿記事 by moba » 8年前

あ、WidthとHeightを間違えていました。
助かりました>_<"! ガードです。

閉鎖

“C言語何でも質問掲示板” へ戻る