《智能指针的标准之争Boostvs.Loki》由会员分享,可在线阅读,更多相关《智能指针的标准之争Boostvs.Loki(13页珍藏版)》请在金锄头文库上搜索。
1、智能指针的标准之争:智能指针的标准之争:Boost vs. Loki 撰文/马维达 撰文/马维达 2001 年 10 月和 2002 年 4 月,在美国的华盛顿和荷兰的安的列斯群岛上分别召开了两次 C+标准会议。会议的内容之一是对一项新的 C+特性提议智能指针(Smart Pointer)进行讨论。本文将对可能成为 C+新标准的两种智能指针方案(Boost vs. Loki)进行介绍和分析,并给出了相应的使用实例。 关键词:智能指针关键词:智能指针 C+ Boost Loki 在现在的标准 C+中,只有一种智能指针:std:auto_ptr。其原因并非是因为 auto_ptr 已足以应付所有
2、相关的工作实际上,auto_ptr 有一个重大的缺陷,就是它不能被用在 STL 容器中而是因为现在的 C+标准在制定时并未能对智能指针进行全面的考察。按照 C+标准委员会成员 Herb Sutter 的说法,只有一种标准的智能指针是一件“可羞”的事情:首先,智能指针所能做的许多有用的事情,是可怜的 auto_ptr 不能完成的;其次,在有些情况下使用 auto_ptr 可能会造成问题,上面所说的不能在容器中使用就是一例。实际上,许多程序员已经开发了各种有用的智能指针,有些甚至在 auto_ptr 被定为标准之前就已存在,但问题是,它们不是标准的。在这样的情况下,C+标准委员会考虑引入新的智能指
3、针,也就是自然而然的事情了。目前进入委员会视野的,主要有两种智能指针方案:Boost 智能指针和 Loki 智能指针。前者是由 C+标准委员会库工作组发起的Boost 组织开发的,而后者由世界级的 C+专家 Andrei Alexandrescu 开发,并在他所著的“Modern C+ Design”一书中进行了详细的阐释。下面,让我们分别来看一看这两种方案各自的技术特点。 一、 一、 Boost 智能指针智能指针 Boost 的智能指针方案实现了五种智能指针模板类,每种智能指针都用于不同的目的。这五种智能指针是: template class scoped_ptr; template cla
4、ss scoped_array; template class shared_ptr; template class shared_array; template class weak_ptr; 下面将分别介绍它们各自的特性,并给出相应的使用实例: ? scoped_ptr:意在用作指向自动(栈)对象的、不可复制的智能指针。该模板类存储的是指向动态分配的对象(通过 new 分配)的指针。被指向的对象保证会被删除,或是在 scoped_ptr 析构时,或是通过显式地调用reset 方法。注意该模板没有“共享所有权”或是“所有权转让”语义。同时,它也是不可复制的(noncopyable) 。正因为
5、如此,在用于不应被复制的指针时,它比 shared_ptr 或 std:auto_ptr 要更安全。与 auto_ptr一样,scoped_ptr 也不能用于 STL 容器中;要满足这样的需求,应该使用 shared_ptr。另外,它也不能用于存储指向动态分配的数组的指针,这样的情况应使用 scoped_array。 下面是使用 scoped_ptr 的一个简单实例: class CTest public: CTest() : m_id(0) CTest(int id) : m_id(id) CTest() std:cout pTest(new CTest); pTest-DoSomethin
6、g(); 其运行结果为: id: 0 - Doing something id: 0 - Destructor is being called (以下的几个例子所用的 CTest 类的定义完全相同,为节省篇幅,不再列出作者) 显然,尽管我们自己没有调用 delete,pTest 仍然为我们正确地删除了它所指向的对象。看起来 scoped_ptr的用途和 auto_ptr 十分类似,但实际上,scoped_ptr 类型的指针的所有权不可转让,这一点是和 auto_ptr相当不同的。 ? scoped_array:该模板类与 scoped_ptr 类似,但意在用于数组而不是单个对象。std:vec
7、tor 可用于替换 scoped_array,并且远为灵活,但其效率要低一点。在不使用动态分配时,boost:array 也可用于替换scoped_array。 下面是一个使用 scoped_array 的实例: void main() boost:scoped_array pTest(new CTest2); pTest0.SetId(0); pTest1.SetId(1); pTest0.DoSomething(); pTest1.DoSomething(); std:cout TestPtr; void PT(const TestPtr TestPtr pTest0(new CTest(
8、0); TestVector.push_back(pTest0); TestPtr pTest1(new CTest(1); TestVector.push_back(pTest1); TestPtr pTest2(new CTest(2); TestVector.push_back(pTest2); std:for_each(TestVector.begin(), TestVector.end(), PT); std:cout pTest1(new CTest2); pTest10.SetId(0); pTest11.SetId(1); std:cout pTest2(pTest1); st
9、d:cout pTest(new CTest); boost:weak_ptr pTest2(pTest); if(boost:shared_ptr pTest3 = boost:make_shared(pTest2) pTest3-DoSomething(); pTest.reset(); assert(pTest2.get() = NULL); 其运行结果为: id: 0 - Doing something id: 0 - Destructor is being called main 函数最后的断言确认了 pTest2 所存储的指针的确已被置为 NULL。 显然,Boost 的智能指针方
10、案会让我们产生这样的疑问:如果我们还需要其他类型的智能指针(比如支持 COM 的智能指针) ,是否意味着我们必须在 C+中再增加智能指针类型,或是采用非标准的实现呢?在泛型技术已得到极大发展的今天,Boost 的“增加增加再增加”的思路是不能让人满意的。正是在这里,我们看到了下面将要介绍的 Loki Smart Pointer 的关键点:通过基于策略(policy-based)的设计来实现通用的智能指针模板。 二、 二、 Loki 智能指针智能指针 按照美国传统辞典(双解)的解释,Loki 是“A Norse god who created discord, especially among
11、his fellow gods.” (斯堪的纳维亚的一个制造混乱的神,尤其是在其同类之间) 。就其给 Boost 智能指针带来的麻烦而言,Loki 智能指针倒真的当得起这个名字;而在另一方面,就其实现的优雅以及功能的强大(也就是说,它给开发者带来的好处)而言,它也的确属于“神族” 。 上面已经说过,Loki 的智能指针方案采用了基于策略的设计。其要点在于把将各功能域分解为独立的、由主模板类进行混合和搭配的策略。让我们先来看一看 Loki 智能指针模板类 SmartPtr 的定义: template class OwnershipPolicy =RefCounted, class Convers
12、ionPolicy =DisallowConversion, template class CheckingPolicy =AssertCheck, template class StoragePolicy =DefaultSPStorage class SmartPtr; 我们可以看到,除了 SmartPtr 所指向的对象类型 T 以外,在模板类 SmartPtr 中包括了这样一些策略:OwnershipPolicy(所有权策略) 、ConversionPolicy(类型转换策略) 、CheckingPolicy(检查策略) 、StoragePolicy(存储策略) 。正是通过这样的分解,使
13、得 SmartPtr 具备了极大的灵活性。我们可以任意组合各种不同的策略,从而获得不同的智能指针实现。下面先对各个策略逐一进行介绍: ? OwnershipPolicy:指定所有权管理策略,可以从以下预定义的策略中选择:DeepCopy(深度复制) 、RefCounted(引用计数) 、RefCountedMT(多线程化引用计数) 、COMRefCounted(COM 引用计数) 、RefLinked(引用链接) 、DestructiveCopy(销毁式复制) ,以及 NoCopy(无复制) 。 ? ConversionPolicy:指定是否允许进行向被指向类型的隐式转换。可以使用的实现有 A
14、llowConversion 和 DisallowConversion。 ? CheckingPolicy:定义错误检查策略。可以使用 AssertCheck、AssertCheckStrict、RejectNullStatic、RejectNull、RejectNullStrict,以及 NoCheck。 ? StoragePolicy:定义怎样存储和访问被指向对象。Loki 已定义的策略有:DefaultSPStorage、ArrayStorage、LockedStorage,以及 HeapStorage。 除了 Loki 已经定义的策略,你还可以自行定义策略。实际上,Loki 的智能指针
15、模板覆盖了四种基本的 Boost 智能指针类型:scoped_ptr、scoped_array、shared_ptr 和 shared_array;至于 weak_ptr,也可以通过定义相应的策略来实现其等价物。通过即将成为 C+标准(C+0x)的 typedef 模板特性,我们还可以利用 Loki 的 SmartPtr 模板来直接定义前面提到的 Boost 的前四种智能指针类型。举例来说,我们可以这样定义shared_ptr: template / typedef 模板还不是标准的 typedef Loki:SmartPtr shared_ptr; 下面是一个使用 Loki “shared_
16、ptr”的实例: typedef Loki:SmartPtr TestPtr; void PT(const TestPtr TestPtr pTest0(new CTest(0); TestVector.push_back(pTest0); TestPtr pTest1(new CTest(1); TestVector.push_back(pTest1); std:for_each(TestVector.begin(), TestVector.end(), PT); std:cout TestPtr;”就可以了。非常的简单! 为了进一步说明 Loki 的“基于策略的设计方法” ,让我们再来看一个更为复杂的例子:通过 Loki:SmartPtr 实现线程专有存储(Thread-Specific Storage,TSS;又