オブジェクトの動的確保

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
りあかー

オブジェクトの動的確保

#1

投稿記事 by りあかー » 3年前

はじめまして。
早速ですがテンプレを使わせていただきます。

[1] 質問文
 [1.1] 自分が今行いたい事は何か

ブロック崩しです。
ブロックをCSVファイルで管理。すなわち、ブロックの数、配置を動的に確保したいです。

 [1.2] どのように取り組んだか(プログラムコードがある場合記載)

コード:


/*一部省略*/
#include "DxLib.h"
#include <vector>
class CGameControl{
	vector<CBlock> *blc;
};

void Init(){
	vector<int> Set_X;
	vector<int> Set_Y;
	for (int j = 0; j < BLOCK_COLUMN; j++) {
		for (int i = 0; i < BLOCK_LINE; i++) {
			if (Csv_Array[i][j] == 1) {
				Set_X.push_back(50 * i);
				Set_Y.push_back(20 * j);
			}
		}
	}
	for (int i = 0; i < Set_X.size(); i++) {
		blc.push_back( new CBlock(Set_X[i], Set_Y[i]) );
	}
}

void All(){
	for (int i = 0; i < Set_X.size(); i++) {
		blc[i]->All() // Drawなどの処理をまとめている
	}
}
 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
式にはクラス型が必要です。といわれます。
vector<CBlock*> blc;
としても今度は大量にエラーがでます。

 [1.4] 今何がわからないのか、知りたいのか

インスタンスの配列の動的確保ができるようにしたい。


[2] 環境  
 [2.1] OS : Windows 10
 [2.2] コンパイラ名 : Visual Studio Community

[3] その他
 そもそもこの設計というのが間違いなんですかね…?
 vector については今回始めて使ってみている程度の知識です。

アバター
usao
記事: 1598
登録日時: 7年前

Re: オブジェクトの動的確保

#2

投稿記事 by usao » 3年前

オフトピック
動的確保とかvectorがどうのという以前に,
まず,もっと基礎の基礎から何とかせねばならないように見受ける……

>ブロックの数、配置を動的に確保したいです
静的であればできるのでしょうか?

りあかー

Re: オブジェクトの動的確保

#3

投稿記事 by りあかー » 3年前

>> usaoさん

基礎の基礎。ですか…。

静的には成功しました。

りあかー

Re: オブジェクトの動的確保

#4

投稿記事 by りあかー » 3年前

すいません。本文プログラムの最後のfor文、条件式は i < blc.size() でした。
失礼しました。

りあかー

Re: オブジェクトの動的確保

#5

投稿記事 by りあかー » 3年前

関数名の前の
CGameControl::
というのも抜けていますね…
すいません…

アバター
みけCAT
記事: 6310
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: オブジェクトの動的確保

#6

投稿記事 by みけCAT » 3年前

りあかー さんが書きました:インスタンスの配列の動的確保ができるようにしたい。
何を「動的確保」と呼んでいるのか分かりませんし、CBlockがどのくらい大きいのかもわかりませんが、
素直な

コード:

/*一部省略*/
#include "DxLib.h"
#include <vector>
class CGameControl{
	vector<CBlock> blc;
};

void Init(){
	vector<int> Set_X;
	vector<int> Set_Y;
	for (int j = 0; j < BLOCK_COLUMN; j++) {
		for (int i = 0; i < BLOCK_LINE; i++) {
			if (Csv_Array[i][j] == 1) {
				Set_X.push_back(50 * i);
				Set_Y.push_back(20 * j);
			}
		}
	}
	for (int i = 0; i < Set_X.size(); i++) {
		blc.push_back( CBlock(Set_X[i], Set_Y[i]) );
	}
}

void All(){
	for (int i = 0; i < Set_X.size(); i++) {
		blc[i].All() // Drawなどの処理をまとめている
	}
}
ではダメなのでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6310
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: オブジェクトの動的確保

#7

投稿記事 by みけCAT » 3年前

さらに、Initのローカル変数Set_XやSet_Yも有効に使っていないようなので、

コード:

/*一部省略*/
#include "DxLib.h"
#include <vector>
class CGameControl{
	vector<CBlock> blc;
};

void Init(){
	for (int j = 0; j < BLOCK_COLUMN; j++) {
		for (int i = 0; i < BLOCK_LINE; i++) {
			if (Csv_Array[i][j] == 1) {
				blc.push_back( CBlock(50 * i, 20 * j) );
			}
		}
	}
}

void All(){
	for (int i = 0; i < blc.size(); i++) {
		blc[i].All() // Drawなどの処理をまとめている
	}
}
の方がいいかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

りあかー

Re: オブジェクトの動的確保

#8

投稿記事 by りあかー » 3年前

>>みけCATさん

返信ありがとうございます。

動的確保というのは、ようはCSVファイルでブロックを管理してもバグらないようにしたい、ブロックの数が変化してもバグらないようにしたい、という意味合いです。という言い方で大丈夫ですかね…?

教えていただいたプログラムですが、それだとブロックをdeleteするタイミングを自由に決められないと思うんですけど、問題ないんですか?
下に詳しく載せますが、下の構造だとシーンを遷移させたタイミングでdeleteということをしなくてもオブジェクトは破棄されるんでしょうか。



あと、もう少し具体的にやっていることを書こうと思います。

まず、プログラム全体の構造ですが、
ゲームプログラミングの館さん
を参考にして作っています。

ただし、Update()とDrawはまとめてAll()というのにしています。

次に、ソースコードをもう少しちゃんとあげますと、

コード:

/* Block.cpp */
#include "Block.h"
#include "DxLib.h"

CBlock::CBlock(int set_X, int set_Y) {
	x = set_X;
	y = set_Y;
	gh_Block = LoadGraph("画像\\ブロック.png");
	GetGraphSize(gh_Block, &width, &height);
	live = true;
}

void CBlock::Draw() {
	if (live) {
		DrawGraph(x, y, gh_Block, true);
	}
}

void CBlock::All() {
	Draw();
}

コード:

/* GameControl.cpp */
#include "GameControl.h"
#include "MyFunc.h"
#include "DxLib.h"

using namespace std;

CGameControl::CGameControl(ISceneChanger *changer) : CBaseScene(changer) {
}

void CGameControl::Init() {
	Rest_Life = 2;
	
	m_ImageHandle = LoadGraph("画像\\ゲーム背景.png");

	Load_Block_Layer("ブロック配置\\ステージ0.csv");
	
	/* このあたりを改善したい */
	vector<int> Set_X;
	vector<int> Set_Y;
	for (int j = 0; j < BLOCK_COLUMN; j++) {
		for (int i = 0; i < BLOCK_LINE; i++) {
			if (Tmp_Array[i][j] == 1) {
				Set_X.push_back(50 * i);
				Set_Y.push_back(20 * j);
			}
		}
	}
	for (unsigned int i = 0; i < Set_X.size(); i++) {
		blc[i] = new CBlock(Set_X[i], Set_Y[i]);
	}
	/*
	for (int i = 0; i < Set_X.size(); i++) {
		blc.push_back(0);
	}
	for (int i = 0; i < Set_X.size(); i++) {
		blc[i] = new CBlock(Set_X[i], Set_Y[i]);
	}
	*/
       
       /**********************************************************/
        
	ply = new CPlayer();
	bll = new CBall();
}

void CGameControl::Final() {
	for (int i = 0; i < BLOCK_LINE*BLOCK_COLUMN; i++) {
		delete blc[i];
	}
	delete ply;
	delete bll;
}

void CGameControl::Operate_Object() {
	for (int i = 0; i < BLOCK_LINE*BLOCK_COLUMN; i++) {
		blc[i]->All();
	}
	ply->All();
	bll->All();
	

	for (int i = 0; i < Rest_Life; i++) { // 残機表示
		DrawCircle(20 + i*(Rest_Life + bll->r + 10), 20, bll->r, GetColor(255, 255, 255));
	}

	if (true == is_GameClear()) {
		bll->vec_X = 0;
		bll->vec_Y = 0;
		m_SceneChanger->ChangeScene(eScene_Menu);
	}

	/* 跳ね返り */
	if ((bll->vec_X != 0) && (bll->vec_Y != 0) && (Rest_Life >= 1)) {
		Check_Ball_Hit_Wall();
	
		if (bll->y > WINDOW_Y) { /*画面の下の方にいったら*/
			bll->x = 320;
			bll->y = 300;
			bll->vec_X = 0;
			bll->vec_Y = 0;
			Rest_Life -= 1;
		}

		Check_Ball_Hit_Block();
	}
	else if (Rest_Life >= 1) {// 球が止まって残機がある = ミス
		DrawFormatString(260, 360, GetColor(255, 255, 255), "PUSH SPACE");
		if (Key_chk[KEY_INPUT_SPACE] == 1) {
			bll->vec_X = 1;
			bll->vec_Y = 1;
		}
	}
	else { // 残機がない = GAME_OVER
		m_SceneChanger->ChangeScene(eScene_Menu);
	}

}

void CGameControl::Draw() {
	CBaseScene::Draw();
}

void CGameControl::All() {
	Draw();
	Operate_Object();
}

bool CGameControl::is_GameClear() {
	for (int i = 0; i < BLOCK_LINE*BLOCK_COLUMN; i++) {
		if (blc[i]->live)return false;
		if (i == BLOCK_LINE*BLOCK_COLUMN - 1)return true;
	}

	return false;
}

void CGameControl::Check_Ball_Hit_Wall() {
	if (bll->x > WINDOW_X) bll->vec_X = -1;
	if (bll->x < 0) bll->vec_X = 1;
	if (bll->y < 0) bll->vec_Y = 1;
	if (bll->x > ply->x && bll->x < (ply->x + ply->width) && (bll->y + bll->r) > ply->y) {
		bll->vec_Y = -1;
	}
}

void CGameControl::Check_Ball_Hit_Block() {
	for (int i = 0; i < BLOCK_LINE*BLOCK_COLUMN; i++) {
		if (blc[i]->live) {
			if (bll->x > blc[i]->x && bll->x < blc[i]->x + blc[i]->width &&
				bll->y + bll->r > blc[i]->y && bll->y + bll->r < blc[i]->y + blc[i]->height) {//上
				blc[i]->live = false;
				bll->vec_Y *= -1;
			}
			if (bll->x > blc[i]->x && bll->x < blc[i]->x + blc[i]->width &&
				bll->y - bll->r > blc[i]->y && bll->y - bll->r < blc[i]->y + blc[i]->height) {//下
				blc[i]->live = false;
				bll->vec_Y *= -1;
			}
			if (bll->x + bll->r > blc[i]->x && bll->x + bll->r < blc[i]->x + blc[i]->width &&
				bll->y > blc[i]->y && bll->y < blc[i]->y + blc[i]->height) {//左
				blc[i]->live = false;
				bll->vec_X *= -1;
			}
			if (bll->x - bll->r > blc[i]->x && bll->x - bll->r < blc[i]->x + blc[i]->width &&
				bll->y > blc[i]->y && bll->y < blc[i]->y + blc[i]->height) {//右
				blc[i]->live = false;
				bll->vec_X *= -1;
			}
		}
	}
}

int CGameControl::Load_Block_Layer(const char *File_Name) {
	FILE *fp;
	errno_t error;
	if ((error = fopen_s(&fp, File_Name, "r")) != 0) {
		return -1;
	}
	for (int j = 0; j < BLOCK_COLUMN; j++) {
		for (int i = 0; i < BLOCK_LINE; i++) {
			if (fscanf_s(fp, "%d,", &Tmp_Array[i][j]) != '\0');
		}
	}
	fclose(fp);
	return 0;
}
という感じです。
中途半端に関数化していて醜いんですけど……。

アバター
みけCAT
記事: 6310
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: オブジェクトの動的確保

#9

投稿記事 by みけCAT » 3年前

りあかー さんが書きました:動的確保というのは、ようはCSVファイルでブロックを管理してもバグらないようにしたい、ブロックの数が変化してもバグらないようにしたい、という意味合いです。という言い方で大丈夫ですかね…?
だとしたら、なおさらnewやnew[]を使うのはメモリリークなどのバグの原因になるので避けるべきでしょう。
りあかー さんが書きました:教えていただいたプログラムですが、それだとブロックをdeleteするタイミングを自由に決められないと思うんですけど、問題ないんですか?
対象環境ややりたいこと、上司や先生などの意見、こだわりなどによりそうだと思います。
りあかー さんが書きました:下に詳しく載せますが、下の構造だとシーンを遷移させたタイミングでdeleteということをしなくてもオブジェクトは破棄されるんでしょうか。
プログラムを終了させればOSが破棄してくれるでしょう。
また、改良したプログラムではblc.clear();で破棄されるはずです。 (オブジェクトの破棄であって、メモリの解放ではありません)
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
usao
記事: 1598
登録日時: 7年前

Re: オブジェクトの動的確保

#10

投稿記事 by usao » 3年前

>それだとブロックをdeleteするタイミングを自由に決められないと思うんですけど、問題ないんですか?

とりあえず,
vector<CBlock> blc;
という形でも良いのか,それとも
vector<CBlock*> blc;
でなければならないのかを明確にしてもらえないと,外部の人間には判断付かない話かと思います.

何らかの理由により後者側でなければならなくて,且つ,blcにnewしたCBlockを格納するという話なのであれば,
いずれどこかでdeleteすべき,ということになるでしょう.


#とりあえず現状でも,ブロックの"最大個数"が,BLOCK_COLUMNとBLOCK_LINE で規定されてはいるけれども,
 ブロックの個数はその範囲の中で可変 なのでは.
オフトピック
CBlock::CBlock()が怒涛の勢いで画像読み込んでそうな

アバター
purin52002
記事: 235
登録日時: 3年前
連絡を取る:

Re: オブジェクトの動的確保

#11

投稿記事 by purin52002 » 3年前

今回の話はvectorを使えば解決だと思うんですが、、、

気になったところを少し挙げます。

[hr]

CGameControlにvector<CBlock> *bicがありますよね?
で、CGameControl::Init()でblc = new CBlock(Set_X, Set_Y);という式があるんですが、おそらくこれは間違いです。

vector<CBlock> *bicというのは、CBlock型のデータを格納する配列、、、のポインタです。
もし、new CBlock(Set_X, Set_Y);のように書きたいのなら、
vector<CBlock*> bicとするべきだと思います。

[hr]

もうひとつ、これはもう少しc++に慣れてからのほうがいいかもしれませんが、、、

c++にはスマートポインタという便利なものがあります。
このスマートポインタは普通のポインタと同じように使えるうえ、newした後は適切なタイミングでdeleteしてくれます。
deleteのし忘れがなくなるのでポインタを使うときはスマートポインタがおすすめです。


オフトピック
上に挙げたスマートポインタは確かに便利ですが、エラーが出ると厄介です。(エラーメッセージが直接的じゃないからわかりづらい^^;
スマートポインタを使う場合はある程度スマートポインタについて勉強してから使うことをお勧めします。
c++初心者を自負しています。
質問者さんには今後私にプログラミングを教えてくれるようにやさしく丁寧に教えるつもりです。ぎぶあんどていく^p^
回答者さんには精一杯感謝します。ぎぶおんりー^p^

りあかー

Re: オブジェクトの動的確保

#12

投稿記事 by りあかー » 3年前

>>みけCATさん
みけCAT さんが書きました: プログラムを終了させればOSが破棄してくれるでしょう。
また、改良したプログラムではblc.clear();で破棄されるはずです。 (オブジェクトの破棄であって、メモリの解放ではありません)
というのは、すなわちCGameControlがdeleteされたタイミングで、blcのデストラクタが呼ばれ、そのデストラクタの中で(自動的に)blc.clear();が実行される、という意味でとって大丈夫でしょうか。

>>usaoさん

私は、「好きなタイミングでコンストラクタ・デストラクタが呼べる、好きなタイミングで生成と消去ができる、から、とりあえずnewしたものを格納したほうがいい」というような解釈をしていたものですから、勝手に後者のほうがいいと思っていました。

しかし、そういうことでもないんですね…。


Offtopicの件は修正しておきます。

りあかー

Re: オブジェクトの動的確保

#13

投稿記事 by りあかー » 3年前

>>purin52002さん
vector<CBlock*> bicとするべきだと思います。
私もそう思って、そのようにしたのですが、エラーメッセージが大量に出ます…。

vector<CBlock*> blc; 部分のエラーメッセージでは

構文エラー:';'が'<'の前にありません。
型指定子がありません -intと仮定しました。
;の前に無効なトークンがあります。

などとでます。

アバター
みけCAT
記事: 6310
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: オブジェクトの動的確保

#14

投稿記事 by みけCAT » 3年前

りあかー さんが書きました:

コード:

/*一部省略*/
#include "DxLib.h"
#include <vector>
class CGameControl{
	vector<CBlock> *blc;
};
実際のコードではvectorが使える状態になっていますか?
すなわち、using std::vector;みたいな文がvectorの前にあるか、本当はstd::vector<CBlock>を使っていますか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
purin52002
記事: 235
登録日時: 3年前
連絡を取る:

Re: オブジェクトの動的確保

#15

投稿記事 by purin52002 » 3年前

CGameControlの宣言をしているファイルで、CBlockの宣言をしているファイルをincludeしていますか?
思い当たる原因はそれぐらいしかないですorz

さんざんポインタの話しといてアレですけどvector<CBlock>で万事解決ではないかと、、、^^;

CGAmeControlがdeleteされたら中身も消えます。

コード:

class MyClass
{
int x;
vector<CBlock> bic;
};
このクラスが使われなくなったらxの値はなくなりますよね?
それと同じ感覚でbicも消えます。

たぶん動的確保=new&deleteにとらわれすぎているのではないでしょうか?
vectorは難しい操作なしに配列の大きさを変えられる便利なクラスですよ^^
c++初心者を自負しています。
質問者さんには今後私にプログラミングを教えてくれるようにやさしく丁寧に教えるつもりです。ぎぶあんどていく^p^
回答者さんには精一杯感謝します。ぎぶおんりー^p^

りあかー

Re: オブジェクトの動的確保

#16

投稿記事 by りあかー » 3年前

>>みけCATさん, purin52002さん

vectorにstd::するのを忘れていました。それが原因だったようです。
しかし、

std::vector<CBlock*> blc;
std::vector<CBlock> blc;

どちらの場合でも成功しました。
凡ミスでしたね…すいません。

最後にOfftopic気味ではあるんですが、
みけCAT さんが書きました: だとしたら、なおさらnewやnew[]を使うのはメモリリークなどのバグの原因になるので避けるべきでしょう。
というのは、すなわちdeleteし忘れたらバグにつながるので、deleteをしなくても自動で消去されるようにnewを使わないようにしたほうが良い、という意味ですかね?

閉鎖

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