如何更好地初始化不可创建的 COM 对象的引用计数器?
我有一个 COM 接口,其中有一个返回对象的方法:
interface ICreatorInterface {
HRESULT CreateObject( IObjectToCreate** );
};
关键是调用 ICreatorInterface::CreateObject()
是检索实现 IObjectToCreate
接口的对象的唯一方法。
在 C++ 中,我可以这样做:
HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
{
//CObjectToCreateImpl constructor sets reference count to 0
CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
if( FAILED(hr) ) {
delete newObject;
}
return hr;
}
或 这种方式
HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
{
//CObjectToCreateImpl constructor sets reference count to 1
CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
// if QI() failed reference count is still 1 so this will delete the object
newObject->Release();
return hr;
}
区别在于引用计数器的初始化方式以及在 QueryInterface() 失败时如何实现对象删除。由于我完全控制了 CCreatorInterfaceImpl
和 CObjectToCreateImpl
,所以我可以选择任何一种方式。
IMO 第一个变体更清晰 - 所有引用计数的东西都在一段代码中。我有监督什么吗?为什么第二种方法会更好?以上哪一个更好,为什么?
I have a COM interface with a method that returns an object:
interface ICreatorInterface {
HRESULT CreateObject( IObjectToCreate** );
};
The key is that calling ICreatorInterface::CreateObject()
is the only way to retrieve an object implementing IObjectToCreate
interface.
In C++ I could do it this way:
HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
{
//CObjectToCreateImpl constructor sets reference count to 0
CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
if( FAILED(hr) ) {
delete newObject;
}
return hr;
}
or this way
HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
{
//CObjectToCreateImpl constructor sets reference count to 1
CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
// if QI() failed reference count is still 1 so this will delete the object
newObject->Release();
return hr;
}
The difference is how the reference counter is initialized and how the object deletion is implemented in case QueryInterface()
fails. Since I fully control both CCreatorInterfaceImpl
and CObjectToCreateImpl
I can go either of ways.
IMO the first variant is clearer - all reference-counting stuff is in one piece of code. Have I overseen something? Why could the second approach be better? Which of the above is better and why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这两种变体都违反了 COM 的一个非常基本的原则
否则会导致各种错误。简单地说,因为它阻止人们对对象进行完全合法的操作。就像把它们放入智能指针一样。智能指针将调用 AddRef,将计数设置为 1,然后 Release 将计数设置为 0 并导致对象自毁。
是的,我意识到 90% 的 QueryInterface 实现都没有这样做。但我也向您保证,有一些可以做到:)
我认为最简单的方法是在创建对象后立即调用 AddRef。这允许对象尽早表现得像普通 COM 对象一样。
我过去遇到过这个问题,并且编写了一个很好的小帮助器方法(假设该对象是在 ATL 中实现的)。
Both variations violate a very fundamental principle of COM
To do otherwise leads to all sorts of errors. Simply put because it prevents people from doing completely legal operations on the object. Like putting them into a smart pointer. The smart pointer would call AddRef, put the count to 1, and later Release putting the count to 0 and causing the object to self destruct.
Yes I realize that 90% of the implementations of QueryInterface don't do this. But I also guarantee you that there are some out there that do :)
I think the simplest approach is to call AddRef immediately after creating the object. This allows the object to behave like a normal COM object at the earliest possible moment.
I've run into this problem in the past and I've written a nice little helper method (assuming the object is implemented in ATL).
Raymond Chen 在他的博客上写了一篇相关文章:
引用计数为零的对象
Raymond Chen wrote a relevant article on his weblog:
On objects with a reference count of zero
我总是使用以下代码场景来创建返回的 com 对象,以避免内存问题。当然,这是可行的,因为我的对象在创建时引用计数 = 0。对我来说,这总是比尝试使用删除运算符处理错误条件更清晰。
I always use the following code scenario for creating returned com objects to avoid issues with memory. Of course this works because my objects are reference counted = 0 when created. This always just seems clearer to me than trying to handle the error condition with using the delete operator.