我知道使用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中,不是将值分配给堆内存,而是指向字符串文字。
现在当我们执行删除时,它会崩溃,因为它没有尝试删除堆内存。 有没有办法知道指针指向堆或堆栈的位置?
由程序员
答案 0 :(得分:2)
只要你需要这些知识,你就已经失去了。为什么?因为即使你省略了错误的删除[],你仍然会有内存泄漏。
创建内存的人应始终是删除内存的人。如果在某些情况下指针可能会丢失(或被覆盖),那么你必须保留一份指针才能正确删除。
答案 1 :(得分:2)
标准C ++中无法确定指针是否指向动态分配的内存。请注意,字符串文字不会在堆栈上分配。
答案 2 :(得分: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
现在让我们区分它们。我将根据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)
上。
堆
理论上你可以假设如果内存既不是全局也不是堆栈 - 它是在堆上分配的。
但实际上这里存在很大的歧义。
您应该知道堆的不同实现(例如HeapAlloc
/ HeapFree
访问的原始Windows堆,或CRT包裹的malloc
/ free
或new
/ delete
)。
只有当您确定它是堆栈/全局指针或通过delete
分配时,您才可以通过new
运算符删除此类块。
总结:
答案 3 :(得分: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
答案 4 :(得分:1)
我认为没有(简单)方法如何判断内存的分配位置(或许可以使用调试器确定它,但这显然不是你想要的)。底线是:永远不要做你在案例2中做的事情。
答案 5 :(得分:0)
在案例2中,MyData =“Value”导致内存泄漏,因为不再引用从new返回的内存。
答案 6 :(得分:0)
这样做没有简单的方法或标准方法。您可以拦截堆分配函数并将每个内存分配区域放在一个列表中。您的“IsHeap”函数应检查传递给函数的区域是否是列表中的区域。这只是一个提示 - 几乎不可能以跨平台的方式做到这一点。
但是又一次 - 为什么你需要那个?