C++では配列を new[] した場合は、delete[] を使います
C++/CLIでデバッグ実行中に、delete_scalar.cpp という画面が出て例外が発生する
VS Version Community 2019, Ver 16.11.42
(詳しくは画像を御覧下さい)
C++/CLIでマネージ型のDLLを作成しています。
int ii = 4;
UINT64* test1 = new UINT64[ii];//例外発生
test1[0] = -9;//何かの処理を行う
delete test1;
↑この様な処理をしたいのですが、UINT64* test1 = new UINT64[ii]; の行を実行すると
delete_scalar.cpp というソースファイルが開き、プログラムが停止します。同時に、ここで例外が発生しているようです。
画像を掲載しますが、なぜこの様な画面が表示されるのか、画面に表示されている内容も理解できません。
プログラムが停止しないようにするには、どうしたら良いですか。
Visual Studio
C++
-
人間 20 評価のポイント
2024-11-19T02:44:15.5666667+00:00 例外発生時の test1[0] の値を確認してみては?
-
huahi11115 335 評価のポイント
2024-11-19T02:51:35.66+00:00 ここまで処理が進まないうちに例外が出ています。この行でブレークすることも不可能です。
また、test1[0] = -9; は誤記でした。test1[0] = 9; と訂正します。
-
人間 20 評価のポイント
2024-11-19T02:55:23.3566667+00:00 だったら、まずは例外発生時のコール スタックを確認することをお勧めします。
-
人間 20 評価のポイント
2024-11-19T04:50:58.1633333+00:00 二重投稿になってしまったので、消しました。
-
huahi11115 335 評価のポイント
2024-11-19T06:01:36.7+00:00 コメントありがとうございます。11:55の投稿はこちらでも読めております。私から削除はしておりません。
お答えいただいた解決法ですが、コールスタックの確認方法等は私の知識が及ばない(それで何かの情報が得られても、読む力が無い)ので、できません。
malloc()を使うことで今回の問題を回避することにします。
-
人間 20 評価のポイント
2024-11-20T05:41:41.51+00:00 対応策を云々する前に、この例外が「誤検知」であるかどうかを確認しておいた方が良いのでは?
(再現環境さえあれば、瞬殺で確認できます。)
参考までに確認手順を示しておきます。
(下記説明は、質問者さんが示したコードを前提としています。)
<"test1" の確認手順>
- 該当プログラムをデバッガ上から実行させ、例外を発生させる。(例外で止まっている状態。)
- Visual Studio デバッガを使用している場合は、[呼び出し履歴] (コール スタック) ウィンドウでの表示で、最上位が "プロフラム.exe!_free_dbg(...)" になっているのを確認する。
- コール スタックの最上位が "プロフラム.exe!_free_dbg(...)" になっている場合、その [呼び出し履歴] リストの中に delete 演算子を呼び出した自分の関数が存在するはずなので、それをクリックする。
- Visual Studio デバッガの [ローカル] ウィンドウに test1 のアドレスが表示されているはずなので、それを確認する。
- [ローカル] ウィンドウ test1 アドレスと、[呼び出し履歴] ウィンドウ _free_dbg() の block アドレスが一致していることを確認する。
- Visual Studio [呼び出し履歴] ウィンドウ タブの隣にある [コマンド ウィンドウ] に切り替え、dq コマンドで test1 の中身を確認する。
例えば上記 3 でのコール スタック最上位の表示が
"プロフラム.exe!_free_dbg(void * block=0x00000216d238cc80, int block_use=0xffffffff)"
となっていた場合、test1 配列の先頭アドレスは 0x00000216d238cc80 になります。
ここで [呼び出し履歴] ウィンドウから [コマンド ウィンドウ] に切り替え、メモリ 0x00000216d238cc80 の中身を確認すればいい。。。ということです。
「誤検知」である場合は、下記のように test1[0] には 0x0000000000000009 がセットされていることが確認できるはずです。
dq 0x00000216d238cc80
0x00000216D238CC80 0000000000000009 cdcdcdcdcdcdcdcd
-
huahi11115 335 評価のポイント
2024-11-22T10:44:03.4466667+00:00 御回答ありがとうございます。
誤検知であるかどうかにかかわらず、デバッガーで何か検知動作が行われて例外が発生したということは、私が示した簡単なコードの部分以外の動作でも異常動作の監視が行われていることになると思います。そこまで監視動作をキャンセルしてしまうのも問題有りだと思います。
従って、既にmalloc()を使ってスマートに解決しました。
-
人間 20 評価のポイント
2024-11-25T00:12:02.6333333+00:00 こんな返信してももぅ意味ないのかもしれませんが、勘違いしているようなので一応。。。。
下記は質問者さんが提示したコードで、malloc 関数にブレークポイントを設定したときのコール スタックです。
(これを見て何も思わないなら、それはそれでいいですけど。)
0:000> k # Child-SP RetAddr Call Site 00 0000009c`8f9efaa8 00007ff6`b1995ec3 hoge!malloc [minkernel\crts\ucrt\src\appcrt\heap\malloc.cpp @ 21] 01 0000009c`8f9efab0 00007ff6`b19951a3 hoge!operator new+0x13 [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp @ 35] 02 0000009c`8f9efaf0 00007ff6`b1994f39 hoge!operator new[]+0x13 [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\heap\new_array.cpp @ 29] 03 0000009c`8f9efb20 00007ff6`b1995e34 hoge!wmain+0x59 04 0000009c`8f9efb80 00007ff6`b1995d5e hoge!invoke_main+0x34 [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 91] 05 0000009c`8f9efbc0 00007ff6`b1995c1e hoge!__scrt_common_main_seh+0x12e [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 06 0000009c`8f9efc30 00007ff6`b1995ea9 hoge!__scrt_common_main+0xe [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 331] 07 0000009c`8f9efc60 00007ffc`56837374 hoge!wmainCRTStartup+0x9 [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\startup\exe_wmain.cpp @ 17] 08 0000009c`8f9efc90 00007ffc`576fcc91 KERNEL32!BaseThreadInitThunk+0x14 09 0000009c`8f9efcc0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
-
huahi11115 335 評価のポイント
2024-11-25T03:11:25.94+00:00 すみません。何も理解できる用語がこの中にありません。独学でこのような低い知識レベルです。ご理解ください。
-
人間 20 評価のポイント
2024-11-25T06:46:28.42+00:00 先に示したコール スタックでは、new [] 演算子でも最終的には malloc() コールにより、ヒープ領域からのメモリ割り当てを行っている事を示しています。
つまり new [] 演算子から malloc() に置き換えたところで、本質的な問題は何も解決されず、臭い物に蓋をしただけ。。。ということではないかと。
-
huahi11115 335 評価のポイント
2024-11-26T05:58:12.12+00:00 色々教えていただきありがとうございます。
int ii=9;
float* test1 = new float[ii];//例外発生
delete[] test1;
これはネットに掲載されていたサンプルプログラムと構造的には変わりません。
これでも例外が発生します。
このコードでも本質的な問題とおっしゃるのでしたら、何が問題か教えて下さい。
ほかの方の開発環境では動作が再現しないというのは理解できております。
こちらでは、ソリューションを新規作成しても同じ例外が出ます。
VS2019を更新インストールしても同じ状況です。
-
人間 20 評価のポイント
2024-11-27T02:31:16.06+00:00 こちらでは再現出来ないので、質問者さんがビルドした exe と pdb ファイルを提供してくれるのであれば、説明は可能です。
サインインしてコメントする
-
gekka 9,916 評価のポイント • MVP
2024-11-17T23:36:00.33+00:00 -
huahi11115 335 評価のポイント
2024-11-18T02:16:18.5666667+00:00 delete[] test1; と記述しても同じく例外が出ます。
UINT64* test1 = new UINT64[ii]; で例外が発生するのですから、deleteに処理は達していません。
-
gekka 9,916 評価のポイント • MVP
2024-11-18T03:29:03.9+00:00 提示されているコードが不完全なので再現できません。
提示されている情報だけだと、間違ったdeleteを行ってしまいメモリが解放漏れとマークされている領域を、newで再利用したタイミングで解放漏れを検出してエラーになっているぐらいしか考えられません。そうだとすると、他の場所で解放漏れをやらかしていることになります。
どこも絶対に間違えていないという自信があるならば、それは誤検知として無視すればいいです。
free_dbgはDEBUGビルドでメモリ解放でリークチェックも行われる関数なので、_CrtSetDbgFlagを事前に設定しておいてチェック無効にすればエラーにならずに実行できるかもしれません。
-
huahi11115 335 評価のポイント
2024-11-18T07:27:31.6+00:00 int ii = 4; float* test1 = new float[ii];
こうしても、例外が発生します。ネットにあるサンプルなので、文法に間違いないと思います。ですから誤検知として無視したいのですが、「誤検知として無視する」方法を教えていただけませんか。
-
gekka 9,916 評価のポイント • MVP
2024-11-18T09:21:50.1633333+00:00 最後に書いてありますよ?
#再現できないので、改善できるかどうかは判りえないです
-
huahi11115 335 評価のポイント
2024-11-18T09:31:35.6166667+00:00 誤検知
ライブラリが内部割り当てを CRT ブロックまたは client ブロックではなく normal ブロックとしてマークした場合、
_CrtDumpMemoryLeaks
によって、メモリ リークが誤って検知されることがあります。 その場合、_CrtDumpMemoryLeaks
では、ユーザー割り当てとライブラリの内部的な割り当てを区別することができません。 ライブラリ割り当てのグローバル デストラクターが、_CrtDumpMemoryLeaks
の呼び出しポイント後に実行される場合、すべての内部ライブラリ割り当てがメモリ リークとして報告されます。 Visual Studio .NET より前のバージョンの標準テンプレート ライブラリによって、_CrtDumpMemoryLeaks
が誤検出を報告する可能性があります。↑これを読んだんですが、方法は書かれていないんですけど。
自分の技術レベルでは、この文章の10%位しかわかりません。
-
gekka 9,916 評価のポイント • MVP
2024-11-18T09:59:40.9266667+00:00 どうして一番最後の行ではなく2番目の行を読むのですか?
-
huahi11115 335 評価のポイント
2024-11-19T02:53:59.7533333+00:00 最後の行とは、どこですか。
なお、今回の不具合、有効な解決方法が見つからない場合はmalloc()を使って回避することにしました。
-
gekka 9,916 評価のポイント • MVP
2024-11-19T18:38:25.8066667+00:00 free_dbgはDEBUGビルドでメモリ解放でリークチェックも行われる関数なので、
_CrtSetDbgFlag
を事前に設定しておいてチェック無効にすればエラーにならずに実行できるかもしれません。が見えませんか?
サインインしてコメントする -