Поскольку большинство пользователей, упомянутых здесь, не имеют стандартного способа узнать, с какой памятью вы имеете дело.
Кроме того, как многие пользователи указали, это случайная извращенная ситуация, когда вы передаете указатель на функцию, которая должна удалять ее автоматически, если она выделена в кучу.
Но если вы настаиваете, тем не менее есть некоторые способы узнать, какая память принадлежит типу.
Вы на самом деле иметь дело с 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
.
В заключение:
- Это своего рода извращенец трюк. Не следует использовать в целом. Лучше предоставить дополнительную информацию указателем, который рассказывает, как его выпустить.
- Вы можете использовать его, только если вы точно знаете, на какую кучу выделена память (в случае, если это куча памяти).
Вам повезло, что вы не получили аварии в первом случае - вы используете 'delete' вместо' delete [] '(или еще лучше,' std :: string'). – avakar
@avakar: Я бы сказал, что ему не повезло - использование 'delete' вместо' delete [] 'является неопределенным поведением с неограниченными последствиями. Никто не знает наверняка, что на самом деле происходит, если реализация очень тщательно изучена. И даже после этого код в unportable. – sharptooth
@avakar: Извините. Я набрал его напрямую. Теперь у меня это изменилось. Спасибо, что указали это. – AKN