Как сказали здесь большинство пользователей, нет стандартного способа узнать, с какой памятью вы имеете дело.
Кроме того, как отмечали многие пользователи, это своего рода извращенная ситуация, когда вы передаете указатель на функцию, которая автоматически удаляет его, если он размещен в куче.
Но если вы настаиваете, тем не менее, есть несколько способов узнать, какая память принадлежит к какому типу.
Вы на самом деле имеете дело с 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
Теперь давайте различим их. Я опишу это с точки зрения Windows API и ассемблера 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)
.
Heap
Теоретически вы можете предположить, что если память не является ни глобальной, ни стековой - она выделяется в куче.
Но здесь на самом деле есть большая двусмысленность.
Вы должны знать, что существуют разные реализации кучи (например, необработанная куча Windows, к которой обращается HeapAlloc
/ HeapFree
, или CRT-оболочка malloc
/ free
или new
/ delete
).
Вы можете удалить такой блок с помощью оператора delete
, только если вы точно знаете, что это был либо стек / глобальный указатель, либо он был выделен с помощью new
.
В заключение:
- Это своего рода извращенный трюк. Не следует использовать в целом. Лучше предоставить некоторую дополнительную информацию с указателем, который говорит, как выпустить его.
- Вы можете использовать его, только если точно знаете, на какую кучу была выделена память (на случай, если это куча памяти).