有效的使用和设计COM智能指针——条款15:以原则中的优先级作为取舍的依据

26 篇文章 0 订阅
25 篇文章 1 订阅

条款15:以原则中的优先级作为取舍的依据

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


中国人常说的“鱼和熊掌不能兼得”,而英语中常说“某某是一把双刃剑”。从本质上来说这都反映了世界矛盾的,我们必须在其中做出取舍。然而,我更倾向于中国人的说法,因为它大有一种在矛盾发生之前就深思熟虑、三思而后行感觉。而等你意识到某种事物确实是一把“双刃剑”时,往往矛盾已经发生了。当然有些矛盾是无法避免的。但是如果我们在设计之初多权衡一下利弊或许我们能从中获得不少设计中的启示,从而绕过一些会让人摔得粉身碎骨的陷阱。

在前面的章节中,你应该了解了一些COM智能指针的使用方法和历史背景。并且你通过示例了解了如何将_com_ptr_tCComPtr编写到代码中。如果你是一个好奇的读者的话,你可能会在心中暗暗嘀咕:“为什么_com_ptr_t这样做?而CComPtr又选择那样来完成同样的事情?”不得不说好奇心是一个很好的老师,他也引导我们进入本条款“在设计原则中斟酌取舍”。

但在开始若干个小结的讨论此之前,我们先给设计的智能指针设计定下两个大原则:

1.它能正确的完成资源管理。[智能]

2.它形如一个指针。[指针]

是的,这两个原则正式“智能”和“指针”的大前提。我们的所有设计问题几乎都是围绕这两个问题进行。当问题的解决办法发生矛盾而无法调和之时,我们可能会优先它的第一个原则,而舍弃第二条原则。毕竟保证程序的正确,而不至于资源泄漏和内存错误才是更为重要的。我们用一个案例来说明:

很多人都应该考虑能否透明的将智能指针替换到原有的代码中去。在一个没有智能指针的世界里,我们这样编写代码:

void SayHello(IFoo *pfoo)
{
    IBar *pbar = 0;
    if (SUCCEEDED(pfoo->GetBar(&pbar)))
    {
        pbar->Hello();
        pbar->Release();
    }
 }


智能指针来了,它带来了诸多的便利之处。因此我们用智能指针替换掉接口指针,代码变成了这般模样:

void SayHello(IFoo *pfoo)
{
    MySmartPointer <IBar> *pbar = 0;
    if (SUCCEEDED(pfoo->GetBar(&pbar)))
    {
        pbar->Hello();
        pbar->Release();     //哦~出问题了。
    }
 }

是的。你一眼就发现上述代码可能会多递减一次引用技术。但如果这个项目如果很老旧,资源申请和释放之间又隔了十万八千里的话。这个隐晦的错误可能不能么容易发现了。

对于这个问题,我曾经想过多种办法,以便使得智能指针能透明的替换掉普通结果指针。但几经周折,最终找到的办法只能将这种危险的操作屏蔽掉以至于不会出现错误(详细了解这个技巧请阅读条款24)

你可能会研究更多的方法以便将智能指针透明的替换到项目中去。那下面这个例子或许或阻止你继续做下去:

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));
    spView->UserIt();
}

上述代码中为平衡引用计数,需要显示做一次Attach操作。原因在于智能指针的赋值运算符会使得引用计数递增一次。而接口指针,却不存在这一问题。

根本原因在于什么?智能指针兼容接口指针的计数方式,付出的代价是使用智能指针时,却应当遵守其特定使用的规则。如果你经常由于对规则生疏而落入陷阱中,可以回顾条款5

因此别妄想透明的引入智能指针到你老旧的项目中去。谨慎的引入智能指针,你需要逐行的审查和修改你的代码。而如果你的项目中正常运行,而并不迫切的需要智能指针给你带来的各种便利之时。我并不推荐你那么做。

让我们回到本条款的主题,智能指针的设计者应该一分为二的看待着这些问题,一方面,对于智能指针引入的不同使用规则,他们又提供了若干函数和手段让你的代码尽可能方便的过渡到这些规则。

1.如Attachdetach函数来调整引用计数。

2.将->Release->AddRef来屏蔽直接对引用计数操作这类危险的动作。

3.提供Release()=NULL来提前释放COM资源。

这正式本条款所遵循的第一个原则:“它能正确的完成资源管理。[智能]”。

另一方面他提供我们一些函数的重载让我们的智能指针可以用近似于接口指针的方式来使用:

1.重载->&等指针相关的操作符。让原有的接口指针代码可以重用。

2.重载<!!=等运算符,使得智能指针能像普通指针一样做关系比较。

3.重载赋值运算符,让智能指针可以如同接口指针一样赋值。

4.重载转换函数,以便让智能指针隐式转换到需要接口指针的地方。

而这是条款所遵循的第二个原则:“它形如一个指针。[指针]”。

你应当明白,智能指针只在底层兼容COM的引用计数规则,而在使用层面,他却有别于接口指针的使用规则【10】(COM智能指针的使用规则请见条款8)。这使得我们透明引入智能指针理想成为泡影,并给我们的开发和维护增加了困难。果断的舍弃透明引入指针的想法,而使得智能指针尽可能正确的完成资源工作是明智的。因为智能指针并非万能,他在解决问题的同时,也引入了新的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值