COM 对象清理

Posted

技术标签:

【中文标题】COM 对象清理【英文标题】:COM Object Clean Up 【发布时间】:2011-01-21 04:20:18 【问题描述】:

下面两行代码有什么区别:

CComPtr< IInterface > m_interface;

IInterface* m_interface;

我知道 CComPtr 有助于消除内存泄漏,但我得到的结果不一致。用CComPtr&lt; IInterface &gt; m_interface;声明指针时 并且在我的 C# 代码中使用该接口没有错误,但是在 VC++ 中使用该接口我得到一个未处理的异常错误,即使我注释掉 IInterface 的实例创建。

我很确定问题出在某个地方:

STDMETHODIMP CSomeClass::get_IClass(IClass** var)
 
      return m_class_var->QueryInterface(var);

STDMETHODIMP CSomeClass::putref_IClass(IClass* var)
 
     m_class_var = var;
     return S_OK;

当我声明接口指针时:IInterface* m_interface; 我在 C# 中测试接口时收到 RPC_E_SERVERFAULT 错误,并且必须显式调用 GC.Collect() 以避免在实例化一些对象后引发错误。在 VC++ 中测试接口时,错误是一致的,但发生的时间不同。如果我注释掉 IInterface 的实例创建,代码运行良好,但是当我尝试创建一个实例时,我得到与以前相同的错误,只是一个模糊的未处理异常错误。我在这里做错了什么?

【问题讨论】:

你真的应该花 15 分钟制作一个很短的 sn-p 来证明问题。 你说“在 VC++ 中使用接口我得到一个未处理的异常错误”——你能告诉我们在 VC++ 中使用接口的代码吗? 【参考方案1】:

CComPtr 是一个智能指针,设计用于在与 COM 惯用语一起使用时做“正确”的事情。

get_IClass 的代码看起来不错,但在存储 putref_IClass 时需要在 IClass 上调用 AddRef。如果你使用CComPtr,那会自动发生。

您需要添加有关 VC++ 未处理异常的更多详细信息。

【讨论】:

谢谢。这有助于更好地理解。我会投票给你,但我没有足够的声望点【参考方案2】:

IInstance* m_instance 是一个指向 IInstance 对象的简单指针。您必须自己管理此指针的生命周期。不像普通对象那样newdelete COM 对象。相反,操作系统会在您调用 WINAPI 函数 `CoCreateInstance' 时分配对象:

// instantiate the CoClass which implements IInstance...
IInstance* instance = 0;
HRESULT hr = CoCreateInstance(__uuidof(mylibrary::MyCoClass), 0, CLSCTX_INPROC_SERVER, __uuidof(mylib::IInstance), &instance);

:   :

// We're done, so release the object...
instance->Release();
instance = 0;

每个 COM 对象都实现了引用计数。当对象的最后一个引用是Release()ed 时,COM 对象会自行销毁。

使用CComPtr&lt;&gt; 可以简化您管理COM 对象生命周期的方式。它是本质上类似于 std::auto_ptr 或 Boost 的 shared_ptr 的智能指针,但它适用于 COM 对象。通常,在使用 CComPtr 时,您将调用 CreateInstance 成员函数而不是调用 WINAPI 函数,并且在完成后您不会显式调用 Release。只要让 CComPtr 超出范围,当它的析构函数被调用时,它会为你调用Release

void function()

  // instantiate the CoClass which implements IMyInterface...
  CComPtr<IInstance> instance;
  instance.CoCreateInstance(__uuidof(mylibrary::MyCoClass));

  :   :

  // We're done, so release the object...
  // dont have to do anything, it will be released when function() exits

【讨论】:

【参考方案3】:

CComPtr m_interface 是一个对象。而 IInterface* m_interface 是一个指针。

第一个将在超出范围时调用其析构函数,我认为(自从我使用它很长时间以来)它会自动调用 m_interface ->Release()。

后者是指向接口的指针,你必须在调用 m_interface->Release() 时进行管理。

你能确认COM对象在访问之前没有被释放吗?

【讨论】:

谢谢。我已经编辑了我的问题以提供更多信息。我在 VC++ 代码测试接口实现中调用 Release()。它没有帮助,我怀疑即使在使用 CComPtr 时我也需要在非托管代码中释放/销毁对象,但我不确定。 @Reggie:有时您确实需要在对象上调用 AddRef/Release,即使它由 CComPtr 管理。您需要向我们展示 VC++ 代码,以便我们查看您是否做错了什么。

以上是关于COM 对象清理的主要内容,如果未能解决你的问题,请参考以下文章

(转)Docker磁盘垃圾清理

ORB.destroy() 没有正确清理并且 ORB 对象实例没有被垃圾收集

java的清理

C++类和对象之对象的初始化和清理

C++类和对象之对象的初始化和清理

Qt 对象清理器