デストラクタ、メモリ解放について

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

デストラクタ、メモリ解放について

#1

投稿記事 by sql » 10年前

龍神録C++を参考にして学習しているのですが、メモリ解放、デストラクタのところで疑問が出てきましたので質問します。
とりあえずコード(DLしたコードをそのまま貼っています)

コード:

#include <DxLib.h>

#include "Key.h"
#include "SystemMgr.h"
#include "Macro.h"
#include "CommonDefine.h"

#define WINDOW_TITLE "東方龍神録"

/*
*	@brief	コンストラクタ
*/
CSystemMgr::CSystemMgr(){
	m_pGameMgr = nullptr;
	m_pFpsCtrl = nullptr;
	SetGraphMode( WIN_W, WIN_H, WIN_BITS ) ;	//解像度設定
	SetMainWindowText(WINDOW_TITLE);			//ウィンドウタイトルをセット
	ChangeWindowMode( TRUE );					//ウィンドウモードに変更
	DxLib_Init();								//DXライブラリ初期化
	SetDrawScreen( DX_SCREEN_BACK );			//描画先を裏画面に設定
	SetOutApplicationLogValidFlag(FALSE);		//ログ出力しない
	SetAlwaysRunFlag(TRUE);						//ウィンドウがノンアクティブでも実行
	SetWindowSizeChangeEnableFlag(TRUE);		//ウィンドウサイズを自由に変更できる
}

/*
*	@brief	デストラクタ
*/
CSystemMgr::~CSystemMgr(){
	if(m_pGameMgr){
		delete m_pGameMgr;	m_pGameMgr=nullptr;
	}
	if( m_pFpsCtrl ){
		delete m_pFpsCtrl;	m_pFpsCtrl=nullptr;
	}
	DxLib_End();							//DXライブラリ終了処理
}

bool CSystemMgr::Initialize(){
	if( m_pGameMgr == nullptr ){
		m_pGameMgr = new CGameMgr();	//STGゲーム部のマネージャー
	}
	if( m_pFpsCtrl == nullptr ){
		m_pFpsCtrl = new CFpsCtrl();	//FPSコントローラー(60FPSに保つもの)
	}
	m_pGameMgr->Initialize();
	return true;
}

/*
*	@brief	終了処理
*/
void CSystemMgr::Finalize(){
}

/*
*	@brief	ゲームのメインループ部
*/
void CSystemMgr::MainLoop(){
	int t=0;
	while( !ScreenFlip() && !ProcessMessage() && !ClearDrawScreen() && !clsDx() ){

		CKey::Inst()->Update();					//UIの状態更新
		
		if( m_pGameMgr->Process() == false ){	//ゲーム処理
			break;
		}

		m_pGameMgr->Draw();						//ゲーム描画

		m_pFpsCtrl->Draw();	//FPS表示
		m_pFpsCtrl->Wait();	//指定FSPを保つための待機

		printfDx("Totl %2d[ms]\n", GetNowCount() - t );	t=GetNowCount();//1周の時間を処理表示

	}
}

コード:

#include <DxLib.h>
#include "SystemMgr.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	CSystemMgr* pSystemMgr = new CSystemMgr;
	if( pSystemMgr->Initialize() )
	{
		pSystemMgr->MainLoop();
	}
	pSystemMgr->Finalize();
	delete pSystemMgr;
	return 0;
}
 
とあります

ここで質問なのですが、
このmain文を見る限り、SystemMgrのmainloopが終わればアプリケーションが終了したということ思うのですが(あくまで「感覚的に」です)。
mainloopを終えたら、ウィンドウを閉じる(プリケーションの終了)しかない→デストラクタ(の記述)必要?という疑問が出てきました
「プリケーションを終了したらメモリはすべて解放される」と聞いたことがあるので、デストラクタで一々delete文を書かなくたって(アプリを終了したらメモリはすべて解放されるから)いいのでは?思った次第です。挙句の果てには「DxLib_End();」を消して実行してみました。

整理しますと、
デストラクタに書いてあるメモリ解放の文を消して実行ー>問題なく実行
DxLib_End();を消して実行ー>問題なく実行
実行されるのは当たり前なのですが。

デストラクタの記述は必要なのか?
そもそもmainファイルでdelete文は必要?(mainloopを抜けちゃったらあとはアプリを終了するしかないのだから)
「プリケーションを終了したらメモリはすべて解放される」というのはあっているのか?

明示的に書くことを避難しているわけではなく、「書かなくても大丈夫なのか?」というニュアンスの質問です。
※あくまで、この龍神録C++についての質問です。

アバター
nullptr
記事: 239
登録日時: 12年前

Re: デストラクタ、メモリ解放について

#2

投稿記事 by nullptr » 10年前

死にたいならそれでもいいんじゃないでしょうか。私はそんな危険なアプリケーション実行したくないですね。

DxLib_End();を消しても問題がなかったのは、OS或いはデバッガが後始末をしてくれただけです。何が怒るかわかりません。
「アプリケーションを終了したらメモリはすべて解放される」というのはスタティックな領域に確保されたメモリのみであり、ヒープメモリは必ずしもその限りではありません。「何が起こるかわからない」と言うべきですかね。
メモリ確保には二種類あります。

int a;

のような記述をすればスタティックな領域に確保され、少なくともアプリケーションが終了するときには破棄されるのは間違いありません。
しかし

int* a = new int;

のように動的に確保したメモリはヒープ領域に確保され、アプリケーションが終了したからと言って破棄される事は保証されません。
メモリを開放しなかった場合、その領域は再利用できなくなります。deleteせずに確保し続ければいずれ利用できるメモリはなくなります。

そうなったらもう何が起きても不思議ではありません。「newしたら必ずdeleteする」というのが約束だと思って下さい。
 
 
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
?
Is the は :
order C++? ✜
     糸冬   
  ――――――――
  制作・著作 NHK
 
 

sql

Re: デストラクタ、メモリ解放について

#3

投稿記事 by sql » 10年前

新々月さん返信ありがとうございます。
新々月 さんが書きました:のように動的に確保したメモリはヒープ領域に確保され、アプリケーションが終了したからと言って破棄される事は保証されません。
なるほど、勉強になります。
新々月 さんが書きました:メモリを開放しなかった場合、その領域は再利用できなくなります。deleteせずに確保し続ければいずれ利用できるメモリはなくなります。
そのメモリを解放して再び利用できるようにする方法はあるのでしょうか?
新々月 さんが書きました:そうなったらもう何が起きても不思議ではありません。「newしたら必ずdeleteする」というのが約束だと思って下さい。
心に刻んでおきます。

また、ここでもう2つだけ質問があります
main文を以下のようにした場合はいつデストラクタが呼び出されるのでしょうか?

コード:

#include <DxLib.h>
#include "SystemMgr.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	CSystemMgr pSystemMgr;// = new CSystemMgr;
	if( pSystemMgr.Initialize() )
	{
		pSystemMgr.MainLoop();
	}
	pSystemMgr.Finalize();
	//delete pSystemMgr;
	return 0;
}
 
2つめは、元のmain文でも上のmain文でも同じく言えることなのですが、アプリをプレイ中に終了させる時です(この場合はmainloopが回ってるのにウィンドウの右上の「閉じる」を押してしまうこと)
この場合は動的に確保したメモリは解放させるのでしょうか(もちろんデストラクタにdelete文が書かれている場合です)要はデストラクタが呼ばれるのか?

知識がないので・・・
お願いします。

アバター
usao
記事: 1889
登録日時: 11年前

Re: デストラクタ、メモリ解放について

#4

投稿記事 by usao » 10年前

>アプリをプレイ中に終了させる時です(この場合はmainloopが回ってるのにウィンドウの右上の「閉じる」を押してしまうこと)

ウィンドウを閉じた瞬間にアプリケーションがぶつっと終了するわけではなく,
ウィンドウを閉じたら MainLoop() を抜けてくることになっていると思います.
(DXライブラリを知らないので,あくまでも憶測ですが,そのようなときにはおそらく
 ProcessMessage() あたりが0か何かを返すようになっているのではないでしょうか.)
ウィンドウを閉じたら何が起こるのか,
Finalize()の行あたりにブレークポイントでも設定して確かめてみるとよいのではないでしょうか.

アバター
usao
記事: 1889
登録日時: 11年前

Re: デストラクタ、メモリ解放について

#5

投稿記事 by usao » 10年前

>main文を以下のようにした場合はいつデストラクタが呼び出されるのでしょうか?
WinMain()を抜けるときです.

コンソールアプリでこういうの↓でも作って実験してみてはどうでしょう.

コード:

class MyClass
{
public:
  ~MyClass(){  std::cout << "MyClass::~MyClass" << std::endl;  };
};

//
void F()
{
  MyClass M;
  std::cout << "end of f()" << std::endl;
}

//
int main()
{
  std::cout << "before f()" << std::endl;
  F();
  std::cout << "after f()" << std::endl;
  return 0;
}

sql

Re: デストラクタ、メモリ解放について

#6

投稿記事 by sql » 10年前

usaoさん返信ありがとうございます!
おかげで理解できました!!

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: デストラクタ、メモリ解放について

#7

投稿記事 by ISLe » 10年前

ウィンドウズのアプリケーションプログラムなら、終了時にヒープメモリが解放されるのは保障されます。
ただし、標準ライブラリからアクセスできる(CRTが管理している)部分に限ります。

DXライブラリはハードウェアリソースにアクセスしているので、その部分はどうなるか分かりません。
DirectXのシステムがその辺り保障してるかもしれませんが、保障されているから書かなくていいことにはなりません。

そもそも再利用のためにdeleteがあるわけですし、リソースを解放しないプログラムはソースコードも再利用性を失います。
解放していないコードを参考にして大きなプログラムを作ったら大変なことになります。
確保と解放を対にするのは将来苦しまないためです。

【23:53追記】
どうやらこの投稿はsqlさんに読まれていないようだ。
さっそく苦しんでいる。

閉鎖

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