大きなメモリ確保の順番

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

大きなメモリ確保の順番

#1

投稿記事 by Ars » 13年前

TaskListクラスはコンストラクタ(int m, int n)でnew char[m*(n+2)]のようにm(n+2)バイトのメモリを確保する、
シューティングゲームで頻繁に敵や弾を出したり消したりすることによって、
メモリの断片化を防ぐ目的のクラスです。
リストの各領域にはTaskクラスが作られ、全ての移動物体はTaskクラスから継承されます。
詳細なコードTask.cppは一番下に貼りました。

これを使い、この順番で確保するとエラーが出ず、

コード:

list1=new TaskList(128, 64);
list2=new TaskList(128, 2048);
list3=new TaskList(128, 256);
list4=new TaskList(128, 256);
list5=new TaskList(128, 2);
この順番で確保するとエラーが出ます。

コード:

list5=new TaskList(128, 2);
list2=new TaskList(128, 64);
list3=new TaskList(128, 2048);
list4=new TaskList(128, 256);
list1=new TaskList(128, 256);
list1~list5はグローバル変数です

エラー
HEAP[001_control.exe]: HEAP: Free Heap block ad35f8 modified at ad3664 after it was freed
Windows によって 001_control.exe でブレークポイントが発生しました。
ヒープが壊れていることが原因として考えられます。001_control.exe または読み込まれた DLL にバグがあります。
あるいは、001_control.exe がフォーカスを持っているときに、ユーザーが F12 キーを押したことが原因として考えられます。
可能であれば、出力ウィンドウに詳細な診断情報が表示されます。

【質問】
「メモリのある領域を重複して解放している」とOSが言っていると思うのですが、
何故そのようなエラーが出るのでしょうか?
また、なぜ順番に依るのでしょうか?

Task.cpp↓

コード:

#include "Task.h"
#include <cassert>

//各タスクは構造体のように前後のタスクへのポインタをメンバに持っている
//リストはアクティブタスクヘッダー、フリータスクヘッダーという、ゲームの処理には直接使われない2つのタスクを持つ
//アクティブタスクヘッダーからつながるタスクがアクティブタスク(使用中のメモリ領域)であり、
//フリータスクヘッダーからつながるタスクがフリータスク(未使用のメモリ領域)である
//削除、挿入も構造体同様に行う

//i番目のタスクを取得
Task*		TaskList::GetTask(size_t i)
{
	return (Task*)(Buffer+TaskSize*i);
}

//タスクリストのコンストラクタ
TaskList::TaskList(size_t size, size_t num)
	: TaskSize(size), TaskNum(num)
{
	//最大タスクサイズはタスク数*2
	Buffer=new char[TaskNum*(TaskSize+2)];

	//アクティブタスクリストの初期化
	//最初はヘッダーだけ
	ActiveTaskHeader=GetTask(0);
	ActiveTaskHeader->prev = ActiveTaskHeader->next = ActiveTaskHeader;

	//フリータスクリストの初期化
	//最初はヘッダーだけ
	FreeTaskHeader=GetTask(1);
	for(size_t i=1; i<TaskNum+2; i++)
	{
		GetTask(i)->prev = 0;
		GetTask(i)->next = GetTask(i+1);
	}
	GetTask(TaskNum+1)->next = FreeTaskHeader;
}

//タスクリストにメモリを確保
//sizeはタスクからあふれないか判定するためだけ使う
void*		TaskList::New(size_t size)
{
	//タスクのサイズが最大サイズを超えていればエラー
	assert(size<=TaskSize);

	//フリータスクが1個もないときはNULLを返す
	if(FreeTaskHeader->next==FreeTaskHeader)
		return 0;

	//フリータスクの先頭からタスクを1個取り出す
	Task* task=FreeTaskHeader->next;
	FreeTaskHeader->next = task->next;
	return task;
}

//タスクのコンストラクタ
//listに新しいタスクを追加
Task::Task(TaskList* list)
{
	//タスクをアクティブタスクリストの末尾に挿入する
	prev = list->ActiveTaskHeader->prev;
	next = list->ActiveTaskHeader;
	prev->next = next->prev=this;
}

//タスクのデストラクタ
Task::~Task()
{
	//タスクをアクティブタスクリストから取りだす
	prev->next=next;
	next->prev=prev;
}

//タスクを削除
void TaskList::Delete(void *p)
{
	//フリータスクを解放してないか?
	Task* task=(Task*)p;
	assert(task->prev!=0);

	//タスクをフリータスクの先頭に挿入
	task->prev = 0;
	task->next = FreeTaskHeader->next;
	FreeTaskHeader->next = task;
}

TaskIter::TaskIter(TaskList* _list)
	:list(_list), task(_list->ActiveTaskHeader)
{}

bool TaskIter::hasNext() {
	return task->next!=list->ActiveTaskHeader;
}

Task* TaskIter::next() {
	return task=task->next;
}

void TaskIter::remove() {
	task=task->prev;
	delete task->next;
}

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

Re: 大きなメモリ確保の順番

#2

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

重複ではなく、ヒープメモリの情報破壊が起きてますよってエラーです。
添字サイズオーバーかポインタのミスか確保していない領域のメモリを書き変えていることになります。

【補足】
順番が関係するのは偶然です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Ars

Re: 大きなメモリ確保の順番

#3

投稿記事 by Ars » 13年前

自己解決しました
23行目のnumとsizeが逆になっていました

失礼しました

閉鎖

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