为啥 AddRef() 和 Release() 的返回类型不是 HRESULT
Posted
技术标签:
【中文标题】为啥 AddRef() 和 Release() 的返回类型不是 HRESULT【英文标题】:Why return type of AddRef() and Release() is NOT HRESULT为什么 AddRef() 和 Release() 的返回类型不是 HRESULT 【发布时间】:2014-02-11 23:59:30 【问题描述】:最近开始学习COM。在 COM 中,函数的返回类型应该是 HRESULT。读过HRESULT
,GetLastError()
的问题,但是为什么,IUnknown 的函数AddRef()
和Release()
有返回类型ULONG
?
我想出的答案是AddRef()
(几乎)总是从QueryInterface()
调用,并且客户端不应该调用它。而对于Release()
,它的返回值永远不会被检查。
虽然我可以用我自己的答案来争论——
对于AddRef()
- 客户可能会遇到必须打电话给它的情况。并且由于客户端可以访问该函数,客户端不会调用它的保证是什么。
对于Release()
- 同样,用户可以检查其返回类型,因为他可以
请澄清。
也像 --> 它的约定是为 COM 相关函数设置 HRESULT 返回类型,而不是强制 --> 如果这是真的,它将停止我大脑中的混乱。
【问题讨论】:
AddRef
和 Release
永远不会失败,所以让他们返回 HRESULT
毫无意义。关于你的最后一个问题:[local]
方法不必返回HRESULT
(尽管如果他们愿意,他们可以);所有其他方法必须返回HRESULT
。这是因为封送层需要能够报告自己的错误(例如,网络故障,如果调用跨越机器边界并且远程主机无法访问)。 AddRef
和 Release
是 [local]
不需要成功/失败状态(参见上面的 Igor),返回值被重用于指示引用计数器的有用的东西。这使得这些非常常用的方法变得轻巧且性能高效。
@IgorTandetnik 感谢您的回复。不过,我仍然认为客户可能需要致电AddRef()
。例如假设客户端有本地接口指针,它将由服务器返回的有效接口指针分配。如果客户端和服务器都是两个不同的进程,它们的地址空间也会不同。因此,如果pIOne
是由服务器发送的,而pIOneTemp
是本地的,那么在声明pIOneTemp = pIOne;
之后,客户端将不得不在pIOneTemp
上调用AddRef()
,因为它位于完全不同的地址空间中。现在为什么它不应该返回HRESULT
?
@RomanR。但是,为什么这不是统一性的突破呢?如果 COM 要求我们编写的方法返回类型为HRESULT
,那么只有它自己的 IUnknown 的方法不符合规则。另请参阅我上面的评论,如果出现这种情况,请解释一下怎么办?
我从未争辩说客户不必致电AddRef
。你觉得我评论的哪一部分可以这样解释?如果客户端永远不必调用AddRef
,那么IUnknown
接口首先就不会提供AddRef
。但这与返回HRESULT
有什么关系?书上是否有规定任何可以调用的方法都必须返回HRESULT
?
【参考方案1】:
“AddRef 和 Release 永远不会失败,因此拥有它们毫无意义 返回 HRESULT。”-Igor Tandetnik
我发布这个作为答案只是因为我的眼睛在阅读整个问题和所有希望帮助某人的 cmet 中流血......来 SO 社区,让我们关闭这些类型的问题。在没有这些垃圾的情况下帮助人们会容易得多。
【讨论】:
【参考方案2】:我问自己一个类似的问题:为什么我们在接口中需要 3 个方法而不是 2 个? QueryInterface 和 Release 应该足够了。 QI 已经做了 AddRef,理论上我们有 2 种方法用于完成基本相同的工作,其中一种应该被淘汰。 QI 做它的事情加上 AddRef。 AddRef 只做 AddRef。 AddRef 死了。亲吻。
现在对于返回类型,我不同意 AddRef/Release 永远不会失败的评论。嗯,他们可以。在几种不同的方式中,它们应该遵循相同的 HRESULT 返回和结果参数规则。
AddRef 失败的一种方式是您可以超过 ULONG_MAX(几乎无法实现,但可能)。或者用于使该调用线程安全的信号量可能会引发异常。很多事情实际上都可能出错,以至于我可以想象规范将其简单地称为 ULONG(void) 的唯一原因是性能,因为调用不带参数的方法要容易得多。
客户端性能早在 90 年代就已经存在,现在绝对不再是问题(除非您谈论的是受限客户端,例如移动设备)。通过以性能的名义牺牲语义,COM 设计实际上造成了长期的维护负担,而牺牲了每个人都知道并且总是消失的短期性能提升(摩尔定律,容量每 18 倍月以相同的成本)。
但即便如此,您也不应该如此频繁地调用 AddRef。这样做意味着您在系统的多个部分携带相同的对象,这本身就是一个糟糕设计的有力指标。
我也不同意这是一个糟糕的问题。这是一个很好的问题,因为它让人们思考。 SO 是关于回答具体问题,因为人们被卡住了。然而,让人们思考宽泛/开放式的问题会教会他们一开始就防止他们陷入困境的技能。
【讨论】:
以上是关于为啥 AddRef() 和 Release() 的返回类型不是 HRESULT的主要内容,如果未能解决你的问题,请参考以下文章
NSMutableArray,removeFromArray 和 release,为啥会崩溃?