1

new を使用して割り当てられたメモリはヒープにそのスペースを取得することを知っているので、メモリ リークを避けるために、プログラムが終了する前にそれを削除する必要があります。

このプログラムを見てみましょう...

Case 1:

char *MyData = new char[20];
_tcscpy(MyData,"Value");
.
.
.
delete[] MyData; MyData = NULL;


Case 2:
char *MyData = new char[20];
MyData = "Value";
.
.
.
delete[] MyData; MyData = NULL;

ケース 2 では、ヒープ メモリに値を割り当てる代わりに、文字列リテラルを指しています。

ヒープメモリを削除しようとしていないため、削除を行うと、予想どおりにクラッシュします。 ポインターがヒープまたはスタックを指している場所を知る方法はありますか?

これでプログラマー

  • スタック メモリを削除しようとしません。
  • 彼は、最初はヒープ メモリを指していたこのポンターが、ローカル リテラルを参照するようになった理由を調査できますか? 途中のヒープメモリはどうしたの?別のポインターでポイントして、他の場所で削除するように作られていますか?
4

7 に答える 7

2

あなたがその知識を必要とするやいなや、あなたはすでに失っています。なんで?その場合、間違ったdelete []を省略しても、メモリリークが発生するためです。

記憶を作成する人は常にそれを削除する人でなければなりません。ある場合にポインタが失われる(または上書きされる)可能性がある場合は、適切に削除するためにポインタのコピーを保持する必要があります。

于 2010-06-07T09:14:47.130 に答える
2

ほとんどのユーザーがここで言ったように、あなたが扱っているメモリを発見する標準的な方法はありません。

また、多くのユーザーが指摘しているように、ヒープに割り当てられている場合は自動的に削除する関数へのポインターを渡すという、ちょっと変わった状況です。

しかし、あなたが主張するならば、それにもかかわらず、どのメモリがどのタイプに属するかを発見するいくつかの方法があります。

あなたは実際に3種類のメモリを扱っています

  • スタック
  • ヒープ
  • グローバル

例えば:

char* p = new char[10]; // p is a pointer, points to heap-allocated memory

char* p = "Hello, world!"; // p is a pointer, points to the global memory

char p[] = "Hello, world!"; // p is a buffer allocated on the stack and initialized with the string

それでは、それらを区別しましょう。これをWindowsAPIとx86アセンブラーの観点から説明します(これは私が知っていることなので:))

スタックメモリから始めましょう。

bool IsStackPtr(PVOID pPtr)
{
    // Get the stack pointer
    PBYTE pEsp;
    _asm {
        mov pEsp, esp
    };

    // Query the accessible stack region
    MEMORY_BASIC_INFORMATION mbi;
    VERIFY(VirtualQuery(pEsp, &mbi, sizeof(mbi)));

    // the accessible stack memory starts at mbi.BaseAddress and lasts for mbi.RegionSize
    return (pPtr >= mbi.BaseAddress) && (pPtr < PBYTE(mbi.BaseAddress) + mbi.RegionSize);
}

ポインタが別のスレッドのスタックに割り当てられている場合は、レジスタ値GetThreadContextを取得するだけでなく、スタックポインタを取得する必要があります。EIP

グローバルメモリ

bool IsGlobalPtr(PVOID pPtr)
{
    MEMORY_BASIC_INFORMATION mbi;
    VERIFY(VirtualQuery(pPtr, &mbi, sizeof(mbi)));

    // Global memory allocated (mapped) at once for the whole executable
    return mbi.AllocationBase == GetModuleHandle(NULL);
}

DLLを作成する場合は、の代わりにモジュールハンドル(実際にはベースマッピングポインタ)を配置する必要がありますGetModuleHandle(NULL)

ヒープ

理論的には、メモリがグローバルでもスタックでもない場合、ヒープに割り当てられていると想定できます。

しかし、実際にはここには大きなあいまいさがあります。

HeapAllocヒープにはさまざまな実装があることを知っておく必要があります( /によってアクセスされる未加工のWindowsヒープHeapFree、またはCRTでラップされたmalloc/freeまたはnew/などdelete)。

deleteこのようなブロックは、スタック/グローバルポインタであるか、またはを介して割り当てられたことが確実にわかっている場合にのみ、演算子を介して削除できますnew

結論は:

  1. それはちょっと変質的なトリックです。一般的には使用しないでください。それを解放する方法を指示するポインターでいくつかの追加情報を提供することをお勧めします。
  2. どのヒープにメモリが割り当てられているかが確実にわかっている場合にのみ使用できます(ヒープメモリの場合)。
于 2010-06-07T10:50:33.117 に答える
2

ポインターがヒープまたはスタックを指している場所を知る方法はありますか?

これは、割り当ての時点で覚えている場合にのみ知ることができます。この場合、ポインタをスマート ポインタ クラスに格納し、これをクラス コードに格納します。

例として使用する場合boost::shared_ptr、これを行うことができます:

template<typename T> void no_delete(T* ptr) { /* do nothing here */ }

class YourDataType; // defined elsewhere
boost::shared_ptr<YourDataType> heap_ptr(new YourDataType()); // delete at scope end

YourDataType  stackData;
boost::shared_ptr<YourDataType> stack_ptr(&stackData, &no_delete); // never deleted
于 2010-06-07T11:00:38.390 に答える
2

標準 C++ では、ポインタが動的に割り当てられたメモリを指しているかどうかを判断する方法がありません。また、文字列リテラルはスタックに割り当てられないことに注意してください。

于 2010-06-07T09:19:35.980 に答える
1

メモリがどこに割り当てられているかを知る(簡単な)方法はないと思います(おそらくデバッガを使用して決定できるかもしれませんが、それは明らかにあなたが望むものではありません)。肝心なのは、ケース 2 で行ったことを決して行わないことです。

于 2010-06-07T09:09:10.257 に答える
0

これを行うための簡単な方法や標準的な方法はありません。ヒープ割り当て関数を傍受し、各メモリ割り当てゾーンをリストに入れることができます。「IsHeap」関数は、関数に渡されたゾーンがリストのものであるかどうかを確認する必要があります。これは単なるヒントです。クロスプラットフォームでこれを行うことはほとんど不可能です。

しかし、もう一度-なぜそれが必要なのですか?

于 2010-06-07T11:42:31.380 に答える
0

ケース 2 では、new から返されるメモリへの参照がなくなるため、MyData = "Value" によってメモリ リークが発生します。

于 2010-06-07T09:18:45.460 に答える