释放 TStreamAdapter 时指针操作无效
Invalid pointer operation when freeing TStreamAdapter
任何人都可以解释为什么我在尝试删除 TStreamAdapter
时得到 "Invalid pointer operation" 吗?或者...如何从 TStreamAdapter
中正确释放内存?它有效,如果我删除 delete
但这会导致内存泄漏。即使我使用 boost::scoped_ptr 它也会因同样的错误而失败。
注意:我也尝试用 soOwned
值初始化 TStreamAdapter
,同样的错误。
代码:
HRESULT LoadFromStr(TWebBrowser* WB, const UnicodeString& HTML)
{
if (!WB->Document)
{
WB->Navigate("about:blank");
while (!WB->Document) { Application->ProcessMessages(); }
}
DelphiInterface<IHTMLDocument2> diDoc = WB->Document;
if (diDoc)
{
boost::scoped_ptr<TMemoryStream> ms(new TMemoryStream);
{
boost::scoped_ptr<TStringList> sl(new TStringList);
sl->Text = HTML;
sl->SaveToStream(ms.get(), TEncoding::Unicode);
ms->Position = 0;
}
DelphiInterface<IPersistStreamInit> diPSI;
if (SUCCEEDED(diDoc->QueryInterface(IID_IPersistStreamInit, (void**)&diPSI)) && diPSI)
{
TStreamAdapter* sa = new TStreamAdapter(ms.get(), soReference);
diPSI->Load(*sa);
delete sa; // <-- invalid pointer operation here???
// UPDATED (solution) - instead of the above!!!
// DelphiInterface<IStream> sa(*(new TStreamAdapter(ms.get(), soReference)));
// diPSI->Load(sa);
// DelphiInterface is automatically freed on function end
return S_OK;
}
}
return E_FAIL;
}
更新:我在这里找到了解决方案 - http://www.cyberforum.ru/cpp-builder/thread743255.html
解决方法是使用
_di_IStream sa(*(new TStreamAdapter(ms.get(), soReference)));
要么...
DelphiInterface<IStream> sa(*(new TStreamAdapter(ms.get(), soReference)));
因为它会在超出范围后自动释放 IStream。至少它应该 - 这里可能存在内存泄漏吗? (CodeGuard 没有检测到任何内存泄漏)。
TStreamAdapter
是 TInterfacedObject
的后代,它实现了引用计数语义。你根本不应该 delete
它,当它不再被任何人引用时,你需要让引用计数释放对象。
使用 _di_IStream
(这只是 DelphiInterface<IStream>
的别名)是使用智能指针自动执行此操作的正确方法。 TComInterface<IStream>
和 CComPtr<IStream>
也可以。
任何人都可以解释为什么我在尝试删除 TStreamAdapter
时得到 "Invalid pointer operation" 吗?或者...如何从 TStreamAdapter
中正确释放内存?它有效,如果我删除 delete
但这会导致内存泄漏。即使我使用 boost::scoped_ptr 它也会因同样的错误而失败。
注意:我也尝试用 soOwned
值初始化 TStreamAdapter
,同样的错误。
代码:
HRESULT LoadFromStr(TWebBrowser* WB, const UnicodeString& HTML)
{
if (!WB->Document)
{
WB->Navigate("about:blank");
while (!WB->Document) { Application->ProcessMessages(); }
}
DelphiInterface<IHTMLDocument2> diDoc = WB->Document;
if (diDoc)
{
boost::scoped_ptr<TMemoryStream> ms(new TMemoryStream);
{
boost::scoped_ptr<TStringList> sl(new TStringList);
sl->Text = HTML;
sl->SaveToStream(ms.get(), TEncoding::Unicode);
ms->Position = 0;
}
DelphiInterface<IPersistStreamInit> diPSI;
if (SUCCEEDED(diDoc->QueryInterface(IID_IPersistStreamInit, (void**)&diPSI)) && diPSI)
{
TStreamAdapter* sa = new TStreamAdapter(ms.get(), soReference);
diPSI->Load(*sa);
delete sa; // <-- invalid pointer operation here???
// UPDATED (solution) - instead of the above!!!
// DelphiInterface<IStream> sa(*(new TStreamAdapter(ms.get(), soReference)));
// diPSI->Load(sa);
// DelphiInterface is automatically freed on function end
return S_OK;
}
}
return E_FAIL;
}
更新:我在这里找到了解决方案 - http://www.cyberforum.ru/cpp-builder/thread743255.html
解决方法是使用
_di_IStream sa(*(new TStreamAdapter(ms.get(), soReference)));
要么...
DelphiInterface<IStream> sa(*(new TStreamAdapter(ms.get(), soReference)));
因为它会在超出范围后自动释放 IStream。至少它应该 - 这里可能存在内存泄漏吗? (CodeGuard 没有检测到任何内存泄漏)。
TStreamAdapter
是 TInterfacedObject
的后代,它实现了引用计数语义。你根本不应该 delete
它,当它不再被任何人引用时,你需要让引用计数释放对象。
使用 _di_IStream
(这只是 DelphiInterface<IStream>
的别名)是使用智能指针自动执行此操作的正确方法。 TComInterface<IStream>
和 CComPtr<IStream>
也可以。