谁拥有IErrorInfo的所有权?

时间:2009-07-29 08:44:02

标签: c++ exception visual-c++ com

我们在代码中使用Native COM支持。一切都很好,除了我们不喜欢在调用错误_com_raise_error()时抛出_com_error异常的事实。由于我们拥有自己的异常层次结构,因此捕获此_com_error很不方便 - 它不在我们的层次结构中,甚至不会从std :: exception继承。

所以我们需要覆盖_com_raise_error()。它本身很容易 - 只需在我们的代码中定义它,链接器就会与它链接。

但不清楚谁拥有IErrorInfo。签名是

void __stdcall _com_raise_error( HRESULT hr, IErrorInfo* info );

所以无论谁调用该函数都将负责在函数返回后调用IErrorInfo :: Release()。但是如果我们在其中抛出异常并且控件将转移到其他地方,该函数将如何返回?

我检查 - 调用AddRef(),然后在进入该函数后立即调用Release() - 引用计数器为1.稍后我们将所有权传递给构造的异常对象 - 它在其构造函数中调用AddRef()并释放()在析构函数中。我认为这是不正确的,因为AddRef()会将引用计数增加到2,但是只会调用一个Release()(在异常析构函数中)。

我是否认为构造函数中的AddRef()会导致内存泄漏,或者是否存在一些不允许IErrorInfo对象泄漏的内部机制?

3 个答案:

答案 0 :(得分:2)

_com_raise_error()无意返回。它必须引发异常,无论其类型如何。如果查看_com_raise_error()的默认实现,则引发的_com_error对象将获取指定的IErrorInfo对象的所有权。 _com_error的构造函数有一个fAddRef参数,其默认值为false,因此不会调用AddRef()。然后,当任何异常处理程序捕获_com_error对象时,将调用Release(),从而释放IErrorInfo对象。

答案 1 :(得分:1)

我认为_com_raise_error会调用SetErrorInfo,并将IErrorInfo对象传递给它。对此的合同是对信息的引用存储在本地线程中,因此无论何时设置新信息,都会释放旧信息。此外,每当有人事后致电GetErrorInfo时,信息的所有权就会转移给该来电者。因此,调用者有义务在每次可能设置失败的调用之后调用GetErrorInfo,并相应地释放对象。

因此,SetErrorInfo(与任何其他常规COM调用一样)将在您的对象上调用AddRef,因此您不能使用计数器1来初始化它。

答案 2 :(得分:1)

添加其他答案,这里有几点想法:

  • 一般的COM规则是in-parameters在任何级别都不需要是AddRef:ed,因为调用是同步的,并且在方法运行时引用计数不能神奇地改变。

    < / LI>
  • 每个AddRef调用都代表一个对该对象的新稳定引用,也就是说,在调用AddRef之后,您可以指望仍在那里的对象。这意味着,如果您想存储一个接口指针供以后阅读,您应该调用AddRef。当您不再关心对象的生存时,请致电Release。

因此,既然你想抛出一个包含IErrorInfo指针的异常对象,那么该对象应该AddRef它,因为它需要指向对象才能生存。它的析构函数通常会释放。

我认为SetErrorInfo不需要参与其中 - 它是抛出异常的C替代方法。