atlc++内存泄漏与安全的ccomobjects
ATL C++ memory leak with safearray of ccomobjects
我发现自己需要帮助。现在,我对c++并不陌生,但是将它与ATL结合起来会带来全新的困惑。无论如何,我的问题是:我(最终)设法在我的COM方法中返回一个对象数组给c#调用者。但是经过"测试"(反复运行上述函数多次),我发现了一个小的内存泄漏。
IDL摘录:
...
interface IDISControl : IDispatch{
...
[id(12)] HRESULT GetNets([out,retval] VARIANT* nets);
};
头摘录:
...
STDMETHOD(GetNets)(VARIANT* nets);
...
代码:STDMETHODIMP CDISControl::GetNets(VARIANT* nets)
{
SNet *netz;
int32_t num;
int result, i;
result = DIS_GetNetNum(securityHandle, &num);
netz = new SNet[num];
result = DIS_GetNet(securityHandle, netz, num); //getting some data
CComSafeArray<IDispatch*> netArray;
CComObject<CDISNet> *net;
CComVariant *var;
netArray.Create(num, 0);
for (i = 0;i<num;i++){
CComObject<CDISNet>::CreateInstance(&net);
if (net == NULL)
return S_FALSE;
net->AddRef();
net->Convert(netz[i]);
netArray[i] = net;
net->Release();
net = NULL;
}
CComVariant val(netArray.Detach());
val.Detach(nets);
delete [] netz;
netArray.Destroy();
return S_OK;
}
我实例化CDISNet对象并在其中放入一些数据(Convert())。我把它们放进保险箱,然后放了出来。据我所知,销毁它们的责任转移给了saferay。然后,我将数组装箱在一个VARIANT中,这样我就可以填充[out, retrieve]参数。因为它是一个out参数,销毁的责任应该转移给调用者(在我的情况下c#,即它的GarbageCollector)。我处理了动态数组'netz',并销毁了数组包装器。
我错过了什么?剩下的分配是什么?(这个项目真的让我很欣赏。net的所有舒适)。
帮助。请。
编辑:进一步的调试告诉我,问题肯定是在我的CComObject对象。它们没有被释放。如果在每次迭代中I delete net;
,数组也会丢失数据。
EDIT2:好吧,我在这段代码周围戳了一下,当我注释掉变体装箱时,泄漏似乎消失了。问题是我从Visual Studio的safearrays示例中借用了这段代码。那么,有没有人知道这是怎么回事:
CComVariant val(netArray.Detach());
val.Detach(nets);
…那该怎么办呢?
大多数(如果不是全部的话)ATL的包装器都遵循COM约定——它们复制/寻址传入数据,因为它们的析构函数将销毁/释放。
因此,当您将分离的SAFEARRAY
传递给CComVariant
的构造函数时,它将复制SAFEARRAY
,这意味着没有人释放CComSafeArray::Detach
的结果。
在这种情况下,我总是发现完全放弃返回值的包装器更容易;
nets->vt = VT_ARRAY | VT_DISPATCH;
nets->parray = netArray.Detach();
另一种方法是将CComSafeArray
直接传递给CComVariant
的构造函数,而不调用Detach
,但这将花费您额外的副本。我更喜欢上面提供的原始访问,因为它是最直接和最便宜的。
对于您的第一次编辑,您使用AddRef/Release
所做的是好的,如果有些不必要的话。CComObject::CreateInstance
返回一个引用计数为0的对象,因此AddRef
将其赋值为1,然后将其赋值给CComSafeArray
将其赋值为2,随后Release
将返回为1。
除非Convert
方法对对象的引用计数做任何事情(例如QueryInterface
本身或将自己传递给另一个COM方法),否则您可以跳过AddRef/Release
对,并让Convert
执行refcount == 0。然后将它添加到数组中会增加它,并且它将一直存在直到释放。
- 从不同线程使用int64的不同字节安全吗
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 虚拟决赛作为安全
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何将元素添加到数组的线程安全函数?
- C++中的线程安全删除
- 通过网络、跨平台传递std::变体是否安全
- 在std::thread中,joinable()然后join()线程安全吗
- 使用std::istream::peek()总是安全的吗
- 从值小于256的uint16到uint8的Endian安全转换
- 在c++队列中使用pop和visit实现线程安全
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 全局变量 多读取器 一个写入器多线程安全?
- 安全到标准:移动会员?
- AcquireCredentialsHandleA() 返回 PFX 文件的0x8009030e(安全包中没有可用的凭据
- 共享队列的线程安全
- boost::文件系统::recursive_directory_iterator多线程安全
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- atlc++内存泄漏与安全的ccomobjects