【问题标题】:Who takes ownership of the IErrorInfo?谁拥有 IErrorInfo 的所有权?
【发布时间】:2009-07-29 08:44:01
【问题描述】:

我们在代码中随意使用 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() 和 Release()在析构函数中。我想这是不正确的,因为 AddRef() 会将引用计数增加到 2,但随后只会调用一个 Release()(在异常析构函数中)。

我是否更正了构造函数中的 AddRef() 会导致内存泄漏,或者是否有一些内部机制根本不允许 IErrorInfo 对象泄漏?

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我想_com_raise_error 将调用SetErrorInfo,将您的IErrorInfo 对象传递给它。其约定是对信息的引用存储在本地线程中,因此每当您设置新信息时,旧信息就会被释放。此外,每当有人在之后拨打GetErrorInfo 时,信息的所有权就会转移给该呼叫者。因此,调用者有义务在每次可能设置它的失败调用后调用GetErrorInfo,并相应地释放对象。

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

      【讨论】:

        【解决方案3】:

        除了其他答案之外,还有一些想法:

        • 一般的 COM 规则是,在任何级别都不需要添加参数,因为调用是同步的,并且在方法运行时引用计数不会神奇地改变。

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

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

        我认为 SetErrorInfo 不需要参与其中——它是引发异常的 C 替代方案。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-10-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-15
          • 2021-10-21
          • 2015-01-22
          相关资源
          最近更新 更多