如果我有一个指向内存的指针,我如何判断它是否指向基于堆的结构(并因此应该被释放)或它是否指向堆栈(因此不应该被触及)?
这是一些示例代码.
TMiniStack<T> = record
private
SP: integer;
fData: array[0..DefaultStackSize - 1] of T;
public
procedure Free;
procedure Push(const Item: T); inline;
function Pop: T; inline;
end;
StaticFactory<T> = class
public type
PStack = ^Stack;
Stack = TMiniStack<T>;
public
class function Create(Size: integer = DefaultStackSize); static;
end;
implementation
Run Code Online (Sandbox Code Playgroud)
我在Free"析构函数"中放置什么来启用记录尝试释放基于堆栈的堆栈?
procedure TMiniStack<T>.Free;
begin
AssertOrLog(@Self is really on the heap,'This stack does not live on the heap');
Finalize(Items, Count);
FreeMemory(@Self);
end;
Run Code Online (Sandbox Code Playgroud)
我似乎记得有一种IsValidPointer方法.但找不到任何相关文档.
我希望能够区分堆栈/堆错误和其他指针问题.
编辑:选择解决方案
为了帮助调试,我添加了一个IsHeapBased: TGUID字段.仅在定义调试时才包含该值.免费方法中的断言检查此并提供反馈.我还添加了一个容量字段(仅调试)来检测堆栈溢出.
此检查的目的仅仅是为了帮助调试.
{$IFDEF DEBUG}
MagicHeapFlag: TGUID = '{EF227045-27A9-4EF3-99E3-9D279D58F9A0}';
{$ENDIF}
class function MiniStack<T>.Create(Size: integer = DefaultSize): PStack;
begin
Result:= AllocMem(SizeOf(TMiniStack<T>) - (DefaultSize * SizeOf(T)) + (Size * SizeOf(T)));
Result.SP:= 0;
{$IFDEF DEBUG}
Result.IsHeapBased:= MagicHeapFlag;
Result.HeapSize:= Size;
{$ENDIF}
end;
{$IFDEF DEBUG}
function TMiniStack<T>.capacity: Integer;
begin
if IsHeapBased = MagicHeapFlag then begin
Result:= HeapSize;
end
else Result:= DefaultSize;
end;
{$ENDIF}
procedure TMiniStack<T>.Free;
begin
{$IFDEF DEBUG}
Assert(IsHeapBased = MagicHeapFlag, 'Do not call free on stack based MiniStacks');
{$ENDIF}
Finalize(Items, count);
FreeMem(@Self);
end;
Run Code Online (Sandbox Code Playgroud)
实际上,您无法以这种方式区分堆栈和堆内存.你说"堆栈",但有很多.每个线程一个.您需要检查所有堆栈的保留地址.如何在不遇到可怕的竞争条件的情况下找到所有堆栈的列表来进行检查?
尝试使记录表现不同取决于它是在堆栈上自动分配还是在堆上动态分配,这是愚蠢的.这些行为变化需要由记录的消费者处理.
让您重新考虑的一个场景是您的记录包含在另一个类型(记录或类)中.包含类型的实例可能是堆分配的,但您不能释放包含的记录,即使它驻留在堆上.
堆分配的底线是您需要记住何时分配堆并确保释放堆上分配的任何内容.如果你忘记了谁通过指针拥有内存你做错了.
不要继续沿着已经开始的死路.