Delphi - TObjectDictionary在Free上提供无效指针

时间:2014-09-03 13:02:15

标签: delphi

Delphi XE6 - 我使用TObjectDictionary,带有自定义类。我创建,添加,以及稍后免费。我只是这样做,一切都很好。如果我执行“TryGetValue”,我会获得免费的“无效指针操作”。 TryGetValue工作正常,给出了正确的结果,但稍后会导致问题...

这是我的代码。

 type
  TWordRec = class
  public
    RemoveAlways: Boolean; // Is this CORP LLC, etc?
    RemoveRestricted: Boolean;
    Replace: Boolean;
    ReplaceWith: string;
    Constructor Create(B1, B2, B3: Boolean; S1: String); overload;
  end;
...
constructor TWordRec.Create(B1, B2, B3: Boolean; S1: String);
begin
  self.RemoveAlways := B1; // Is this CORP LLC, etc?
  self.RemoveRestricted := B2;
  self.Replace := B3;
  self.ReplaceWith := S1;
end;

我在按钮上添加测试代码......

procedure TForm1.Button1Click(Sender: TObject);
var
CurrentDictEntry : TWordRec;
FoundIt : Boolean;

begin

ReportMemoryLeaksOnShutdown := True;

WordDict := TObjectDictionary<String, TWordRec>.Create([doOwnsValues]);
WordDict.Add('CO', TWordRec.Create(True, False, False, ''));
WordDict.Add('CORP', TWordRec.Create(True, False, False, ''));
WordDict.Add('CORPORATION', TWordRec.Create(True, False, False, ''));

CurrentDictEntry := TWordRec.Create(False, False, False, '');

// If I remove next two code lines, everything is fine
// With these 2 lines, I get error ON WordDict.Free;
FoundIt := WordDict.TryGetValue('CORP', CurrentDictEntry);
if FoundIt = True then ShowMessage('Found');

CurrentDictEntry.Free;
WordDict.Free;
end;

为什么我不能释放我的WordDict?如果我只是释放WordDict(即注释掉CurrentDictEntry.free),WordDict.Free在没有无效指针操作的情况下工作,但是在退出我的应用程序时出现内存泄漏。

1 个答案:

答案 0 :(得分:3)

主要问题在于:

CurrentDictEntry.Free;

此时,CurrentDictEntry是容器中包含的值。并且您无法释放此容器中的值,因为容器拥有它们。如果你试图释放值,那么容器稍后会尝试再次释放它们,这是经典的双重免费问题。

一旦你告诉容器拥有这些值,你就不能释放它们。

另一个问题是你泄漏TWordRec

CurrentDictEntry := TWordRec.Create(False, False, False, '');
FoundIt := WordDict.TryGetValue('CORP', CurrentDictEntry);

第一行创建一个新对象,并在CurrentDictEntry中保存对它的引用。第二行然后覆盖CurrentDictEntry,现在你根本没有对你刚刚创建的对象的引用,因此它被泄露了。

您的代码应如下所示:

ReportMemoryLeaksOnShutdown := True;

WordDict := TObjectDictionary<String, TWordRec>.Create([doOwnsValues]);
try
  WordDict.Add('CO', TWordRec.Create(True, False, False, ''));
  WordDict.Add('CORP', TWordRec.Create(True, False, False, ''));
  WordDict.Add('CORPORATION', TWordRec.Create(True, False, False, ''));

  FoundIt := WordDict.TryGetValue('CORP', CurrentDictEntry);
  if FoundIt then 
    ShowMessage('Found');
finally
  WordDict.Free;
end;