有效的使用和设计COM智能指针 ——条款16:智能指针的引入不能违反COM引用计数规则

探讨了在COM编程中使用智能指针时如何避免违反引用计数规则,通过对比不同实现方式,强调了正确管理资源的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

条款16:智能指针的引入不能违反COM引用计数规则

更多条款请前往原文出处:http://blog.youkuaiyun.com/liuchang5

我们之前已经看过类似的函数。它是严格遵照了引用计数的规则而编写的:

IView* GetView(int nIndex)
{
    IView* pView = m_Views[nIndex];
    pView->AddRef();             //引用计数被增加了一次。
    return pView;
}

这样没错,但是你可能觉得使用起来就不太方便了:

void UseView(int nIndex)
{
    CComPtr<IView> spView = NULL;
    spView.Attach(GetView(0));        //这里需要用Attach将其绑定到智能指针之上
    spView->UserIt();
}

你可能会做这样的考虑。如果能想办法改造一下GetView,之后AttachDetach操作就能从智能指针的实现中剔除出去。那样智能指针的设计和使用都将得到简化。

CComPtr<IView> GetView(int nIndex)
{
    CComPtr<IView> pView = m_Views[nIndex];
    return pView;
}

貌似这样看上去很好。但她却实属一个糟糕的设计。如果使用他的人如此操作这一指针,那你是幸运的:

CComPtr<IView> spIView   = NULL;
spIView = GetView();
spIView->DoSomething();

嗯,一切都正常的进行着。并且你自己揣摩着智能指针拷贝时候的引用计数。发现它没有混乱,而且井井有条。但这也仅仅是在你完全使用智能指针对资源进行管理的情况下。如果使用者没有在函数返回处用智能之中接收接口指针,而使用如下这样的方式,那么就不容乐观了:

IView *pIView   = NULL;
pIView = GetView();
pIView->DoSomething();

可以想象,这个时候由于智能指针出栈,引用计数已经归0。那么pIView已经指向了一个被释放的COM组件。

或许你还想亡羊补牢,做一些补救措施,让他能继续工作:

IView *pIView   = NULL;
pIView = GetView();
pIView ->AddRef();             //这种挽留已经为时过晚
pIView->DoSomething();

这已经为时过晚了,试想如果GetView中传出的接口引用计数为1,那么当返回值被析构,引用计数归0,此时组件已经被释放得干干净净了。但之后你却调用了一次AddRef()试图对引用计数的递减做一些挽留。这样一来迎接你的只会是是内存错误。

让我们总结一下上面这些糟糕的代码,看看他们有哪些错误之处。首先,它仍然违反了条款3中“别让智能指针存在于接口的参数和返回值中”,这再一次体现了由于不遵守这个重要条款而带来的副作用。其次他企图去改变COM引用技术的规则:在GetView()之后再次调用了AddRef()。幸好犯罪未遂。

那之所以有人想这么做的目的是什么呢?额我想他可能认为诸如此类的方法可以将AttachDetach这样的函数从智能指针中剔除出去,这样能使得智能指针的设计和使用更加的优雅。

但请谨记在心:设计的智能指针不能违反COM接口的引用计数规则。纵使你有办法让代码完全使用智能指针对资源进行管理,而不出现COM引用计数遗留下来的若干问题。但也请你照顾接口指针的引用技术规则,他会让你的智能指针被更多的地方所使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值