根据MSDN:
对于
[out]
参数,方法或属性分配内存和 调用者负责释放内存。
其中哪些都可以:
[...]
STDMETHOD(Method)([out] BSTR* psValue)
[...]
BSTR myBStr1;
Method(&myBStr1);
::SysFreeString(myBStr1);
BSTR myBStr2 = SysAllocString(L"MyStringValue");
Method(&myBStr2);
::SysFreeString(myBStr2);
BSTR myBStr3 = NULL;
Method(&myBStr3);
::SysFreeString(myBStr3);
答案 0 :(得分:4)
是的,垃圾是可以接受的。该方法负责初始化该值。来电者只负责释放。
out attribute上的MSDN:
远程时,假定[out] -only参数未定义 调用过程并为该对象分配内存 服务器
#1,#3没问题。 #2会造成内存泄漏。
这条规则实际上造成了一些混乱。如果方法返回错误,您可能不确定值是否已初始化。如果您尝试释放垃圾,它将导致访问冲突或损坏内存。如果你跳过内存释放和部分成功的方法留下了一些有意义的东西(好吧,这是服务器端的问题,但仍然),那么你泄漏内存。在调用之前使用NULL
进行初始化肯定更安全,例如,CComBSTR
构造函数会为您执行此操作。在服务器端,您可能希望使用{out}值的NULL
初始化来启动方法,以免在以后意外地将它们保留为未初始化。
答案 1 :(得分:3)
从编组调用的角度看规则(即,当对象位于不同的COM公寓中时,或者当它存在于不同的进程或机器中时会发生什么);你会理解规则是如何运作的,以及为什么它是唯一明智的规则。
关键的事实是,对于[out]
参数,编组器不将初始值编组为被调用者。
这意味着在拨打电话之前放入变量的内容并不重要。它可以是垃圾或NULL。没有人会去看它。
注意:这也意味着如果变量在调用之前包含需要释放的内容,则必须在调用之前自行释放它,否则它将被泄露。编组器不会为你释放它(因为作为参数[out]
编组器必须假定它是垃圾)并且被调用者即使它想要也不能释放它(因为它永远不会从它获得现有的值) mashaller)。
其次,在调用返回后,被调用者无法知道你对返回值做了什么,所以唯一可以释放参数的是调用者。
错误条件的情况有点儿。
原则上,COM要求在返回之前必须将[out]
参数设置为一致(“marshallable”?)值(NULL或等效或有效值),即使存在错误。这也是“唯一明智的规则”:编组人员无法知道被调用者处于错误状态。它也不会基于HRESULT进行猜测,因为即使是“错误类”HRESULT也不意味着该方法不打算将值返回给调用者。 marshaller会将参数的值编组回调用者 - 错误或没有错误 - 因此参数更有效,或者编组本身会崩溃。
在实践中......好吧,有些对象比其他对象编写得更好,有些COM类从不通过编组调用,因此类的开发人员从不会遇到问题。不符合这些规定的课程不能在公寓内安全使用。
即使面对错误情况,确保参数值保持一致的规范方法看起来像这样:
STDMETHODIMP Class::Method(BSTR *pValue)
{
*pValue = NULL; // 1) Initialize all the [out] parameters before
// doing anything, to make sure they are always
// consistent
BSTR tempValue; // 2) Use a temporary to hold any result value
... // 3) Use the temporary for all computations
... // Finish all other processing
*pValue = tempValue; // 4) Only after all possible error conditions
// are behind us, do put the new value
// in the output parameter
return S_OK;
}
显然,如果out参数只是一个不需要释放的值(比如int等),那么这一切都不重要。