boost - 智能指针介绍
2001 年10 月和2002 年4 月,在美国的华盛顿和荷兰的安的列斯群岛上分别召开了两次C++标准会议。会议的内容之一是对一项新的C++特性提议——智能指针(Smart Pointer)——进行讨论。本文将对可能成为C++新标准的两种智能指针方案(Boost vs. Loki)进行介绍和分析,并给出了相应的使用实例。 关键词:智能指针 C++ Boost Loki 在现在的标准C++中,只有一种智能指针:std::auto_ptr。其原因并非是因为auto_ptr 已足以应付所有相关的工作——实际上,auto_ptr 有一个重大的缺陷,就是它不能被用在STL 容器中——而是因为现在的C++标准在制定时并未能对智能指针进行全面的考察。按照C++标准委员会成员Herb Sutter 的说法,只有一种标准的智能指针是一件“可羞”的事情:首先,智能指针所能做的许多有用的事情,是可怜的auto_ptr 不能完成的;其次,在有些情况下使用auto_ptr 可能会造成问题,上面所说的不能在容器中使用就是一例。实际上,许多程序员已经开发了各种有用的智能指针,有些甚至在auto_ptr 被定为标准之前就已存在,但问题是,它们不是标准的。在这样的情况下,C++标准委员会考虑引入新的智能指针,也就是自然而然的事情了。目前进入委员会视野的,主要有两种智能指针方案:Boost 智能指针和Loki 智能指针。前者是由C++标准委员会库工作组发起的Boost 组织开发的,而后者由世界级的C++专家Andrei Alexandrescu 开发,并在他所著的“Modern C++ Design”一书中进行了详细的阐释。下面,让我们分别来看一看这两种方案各自的技术特点。 一、 Boost 智能指针 template<typename T> class scoped_ptr; 下面将分别介绍它们各自的特性,并给出相应的使用实例: scoped_ptr:意在用作指向自动(栈)对象的、不可复制的智能指针。该模板类存储的是指向动态分配的对象(通过new 分配)的指针。被指向的对象保证会被删除,或是在scoped_ptr 析构时,或是通过显式地调用reset 方法。注意该模板没有“共享所有权”或是“所有权转让”语义。同时,它也是不可复制的(noncopyable)。正因为如此,在用于不应被复制的指针时,它比shared_ptr 或std:auto_ptr 要更安全。与auto_ptr一样,scoped_ptr 也不能用于STL 容器中;要满足这样的需求,应该使用shared_ptr。另外,它也不能用于存储指向动态分配的数组的指针,这样的情况应使用scoped_array。 下面是使用scoped_ptr 的一个简单实例: class CTest 其运行结果为: 显然,尽管我们自己没有调用delete,pTest 仍然为我们正确地删除了它所指向的对象。看起来scoped_ptr的用途和auto_ptr 十分类似,但实际上,scoped_ptr 类型的指针的所有权不可转让,这一点是和auto_ptr相当不同的。 scoped_array:该模板类与scoped_ptr 类似,但意在用于数组而不是单个对象。std::vector 可用于替换scoped_array,并且远为灵活,但其效率要低一点。在不使用动态分配时,boost::array 也可用于替换scoped_array。 下面是一个使用scoped_array 的实例: void main() 其运行结果为: shared_ptr:意在用于对被指向对象的所有权进行共享。与scoped_ptr 一样,被指向对象也保证会被删除,但不同的是,这将发生在最后一个指向它的shared_ptr 被销毁时,或是调用reset 方法时。shared_ptr符合C++标准库的“可复制构造”(CopyConstructible)和“可赋值”(Assignable)要求,所以可被用于标 下面的例子演示怎样将shared_ptr 用于std::vector 中: typedef boost::shared_ptr<CTest> TestPtr; 其运行结果为: 运行结果中的“use count”是通过shared_ptr 的use_count()方法获得的“使用计数”,也就是,对所存储指针进行共享的shared_ptr 对象的数目。我们可以看到,在通过new 分配了3 个CTest 对象,并将相应的shared_ptr 对象放入TestVector 后,三个使用计数都为2;而在我们使用reset()方法复位pTest0、pTest1 和pTest2 后,TestVector 中的各个shared_ptr 对象的使用计数变成了1。这时,我们调用TestVector的clear()方法清除它所包含的shared_ptr 对象;因为已经没有shared_ptr 对象再指向我们先前分配的3个CTest 对象,这3 个对象也随之被删除,并导致相应的析构器被调用。 shared_array:该模板类与shared_ptr 类似,但意在用于数组而不是单个对象。指向std::vector 的shared_ptr 可用于替换scoped_array,并且远为灵活,但其效率也要低一点。 下面是使用实例: void main() 其运行结果为: weak_ptr:该模板类存储“已由shared_ptr 管理的对象”的“弱引用”。要访问weak_ptr 所指向的对象,可以使用shared_ptr 构造器或make_shared 函数来将weak_ptr 转换为shared_ptr。指向被管理对象的最后一个shared_ptr 被销毁时将删除该对象,即使仍有weak_ptr 指向它也是如此。与原始指针不同的是,届时最后一个shared_ptr 会检查是否有weak_ptr 指向该对象,如果有的话就将这些weak_ptr 置为空。这样就不会发生使用原始指针时可能出现的“悬吊指针”(dangling pointer)情况,从而获得更高的安全水平。 void main() 其运行结果为: 显然,Boost 的智能指针方案会让我们产生这样的疑问:如果我们还需要其他类型的智能指针(比如支持COM 的智能指针),是否意味着我们必须在C++中再增加智能指针类型,或是采用非标准的实现呢?在泛型技术已得到极大发展的今天,Boost 的“增加增加再增加”的思路是不能让人满意的。正是在这里,我们看到了下面将要介绍的Loki Smart Pointer 的关键点:通过基于策略(policy-based)的设计来实现通用的智能指针模板。 二、 Loki 智能指针 template 我们可以看到,除了SmartPtr 所指向的对象类型T 以外,在模板类SmartPtr 中包括了这样一些策略:OwnershipPolicy(所有权策略)、ConversionPolicy(类型转换策略)、CheckingPolicy(检查策略)、StoragePolicy(存储策略)。正是通过这样的分解,使得SmartPtr 具备了极大的灵活性。我们可以任意组合各种不同的策略,从而获得不同的智能指针实现。下面先对各个策略逐一进行介绍: OwnershipPolicy:指定所有权管理策略,可以从以下预定义的策略中选择:DeepCopy(深度复制)、RefCounted(引用计数)、RefCountedMT(多线程化引用计数)、COMRefCounted(COM 引用计数)、RefLinked(引用链接)、DestructiveCopy(销毁式复制),以及NoCopy(无复制)。 除了Loki 已经定义的策略,你还可以自行定义策略。实际上,Loki 的智能指针模板覆盖了四种基本的Boost 智能指针类型:scoped_ptr、scoped_array、shared_ptr 和shared_array;至于weak_ptr,也可以通过定义相应的策略来实现其等价物。通过即将成为C++标准(C++0x)的typedef 模板特性,我们还可以利用Loki 的SmartPtr 模板来直接定义前面提到的Boost 的前四种智能指针类型。举例来说,我们可以这样定义: shared_ptr: 下面是一个使用Loki “shared_ptr”的实例: typedef Loki::SmartPtr<CTest> TestPtr; void main() 其运行结果为: 前面已经提到,要通过Loki 定义与Boost 的shared_ptr 功能等价的智能指针,除了第一个模板参数以外,其他的参数都可以使用缺省值,所以在上面的例子中,我们直接使用“typedef Loki::SmartPtr<CTest> TestPtr;”就可以了。非常的简单! 为了进一步说明Loki 的“基于策略的设计方法”,让我们再来看一个更为复杂的例子:通过Loki::SmartPtr 实现线程专有存储(Thread-Specific Storage,TSS;又称线程局部存储,Thread Local Storage,TLS)。 所谓线程专有存储,是指这样一种机制,通过它,多线程程序可以使用一个逻辑上的全局访问点来访问线程专有的数据,并且不会给每次访问增加额外的锁定开销。举一个简单的例子,在C 语言中,我们可以通过errno变量来获取错误代码;通常errno 就是一个普通的全局变量——在单线程环境中,这当然没有什么问题,但如果 显然,智能指针的语义能够很好地适用于TSS。我们可以编写一种智能指针,使得所有对其所指向对象的访问都成为线程专有的——也就是说,每个线程访问的实际上是自己专有的对象,但从程序的外表来看,却都是对同一对象的访问。有了Loki::SmartPtr,我们可以非常容易地实现这样的智能指针:如其名字所指示的,TSS 涉及的是存储问题,我们只要对Loki::SmartPtr 的StoragePolicy 进行定制就可以了,其他的工作可以交给Loki::SmartPtr 去完成。 在POSIX PThreads 库和Win32 中都提供了用于线程专有存储的函数,它们分别是pthread_key_create、pthread_setspecific、pthread_getspecific 和pthread_key_delete(POSIX PThreads 库),以及TlsAlloc、TlsSetvalue、TlsGetvalue 和TlsFree(Win32)。关于这些函数的详细信息,请参阅相关的文档。 下面给出在MSVC 6.0 下实现的用于TSS 的StoragePolicy,并通过注释逐行进行分析(这个实现使用了PThreads-Win32 库,这是一个Win32 上的PThreads 实现。使用Win32 的线程专有函数也可以实现类似的StoragePolicy,但编写在线程退出时调用的CleanupHook()却需要一点“窍门”。具体方法可参考Boost 的thread_specific_ptr 实现): namespace Loki // 用于模拟typedef template 的结构。 下面让我们来看一个使用实例。首先让我们先定义: Loki::SmartPtr 其含义为:定义一种智能指针,被它指向的类型是int,OwnershipPolicy 是NoCopy,ConversionPolicy是DisallowConversion,CheckingPolicy 是NoCheck(因为TS 对象存储方式的限制,这是惟一能和TS_SPStorage 一起使用的CheckingPolicy。读者可自行尝试找到更好的解决方案),StoragePolicy 是TS_SPStorage。 pthread_mutex_t io_mutex = NULL; // iostreams 不一定是线程安全的! void main(int argc, char* argv[]) 其运行结果为: 由此我们可以看出,尽管看起来在各个线程中访问的都是同样的*value,但实际上访问的却是各自的线程专有的对象。而且除了初始化以外,对这些对象的访问无需进行序列化。因为Loki::SmartPtr 为我们做了大量的工作,TS_SPStorage 的实现十分简洁明了。有兴趣的读者,可以对这里的实现与Boost 的thread_specific_ptr 进行比较。像这样对Loki::SmartPtr 的策略进行的定制,在理论上数目是无限的,也就是说,通过它我们可以拥有五花八门、“千奇百怪”的智能指针——了不起的Loki,不是吗?有了这样的模板类,我们就再不需要一次一次地为标准C++增加新的智能指针类型了。 三、 结束语 相关资源 |
boost - 智能指针介绍相关推荐
- 在你的代码中使用Boost智能指针
在你的代码中使用Boost智能指针 Smart Pointers to boost your code(By peterchen) 翻译 masterlee Download source file ...
- Boost智能指针——shared_ptr
boost::scoped_ptr虽然简单易用,但它不能共享所有权的特性却大大限制了其使用范围,而boost::shared_ptr可以解决这一局限.顾名思义,boost::shared_ptr是可以 ...
- Boost智能指针——weak_ptr
循环引用: 引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象.一个简单的例子如下: #include <string> #include <ios ...
- Boost智能指针——boost::scoped_ptr(使用及原理分析)
简介 boost::scoped_ptr是一个比较简单的智能指针,它能保证在离开作用域之后它所管理对象能被自动释放.下面这个例子将介绍它的使用: 1 #include <iostream> ...
- boost智能指针之shared_ptr,scoped_ptr,intrusive_ptr,weak_ptr源码简析
boost库实现了各种智能指针,基本上都纳入了c++11标准中,boost库的smart_ptr目录下就是各种指针的实现了: 1.shared_ptr template<class T> ...
- [转] Boost智能指针——scoped_ptr
http://www.cnblogs.com/tianfang/archive/2008/09/15/1291050.html boost::scoped_ptr和std::auto_ptr非常类似, ...
- Boost智能指针——scoped_ptr
boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放.下列代码演示了该指针的基本应用: #include<stri ...
- boost any 实现万能容器_全面剖析 C++ Boost 智能指针!| CSDN 博文精选
作者 | .NY&XX 责编 | 屠敏 出品 | CSDN 博客 为什么要使用智能指针 C++没有提供类似JAVA的垃圾回收机制,因此Boost可以通过智能指针来管理内存避免一些问题.C++继 ...
- 全面剖析 C++ Boost 智能指针! | CSDN 博文精选
作者 | .NY&XX 责编 | 屠敏 出品 | CSDN 博客 为什么要使用智能指针 C++没有提供类似JAVA的垃圾回收机制,因此Boost可以通过智能指针来管理内存避免一些问题.C++继 ...
- C++智能指针剖析(上)std::auto_ptr与boost::scoped_ptr
1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...
最新文章
- 高精地图:为自动驾驶汽车提供动力的新时代地图
- 业界首个!华为联合中国信通院等发布《网络体系强基展望白皮书》
- FJ省队集训DAY4 T1
- 我们为什么不能只用O记号来谈论算法?
- 突发!Redis之父退出:不在维护Redis项目
- 【HDU - 薛猫猫杯程序设计网络赛】【题解】
- duri oracle 连接字符串_C#连接Oracle数据库的连接字符串
- 2020统计局的行政划分表_湖州市有几个区和县?湖州市2020年县级以上区划名单...
- 真的已经讲烂了!java字符串转对象
- 面向对象设计模式与原则
- ASP.NET XML Web 服务的应用程序集成
- 电脑坏了,疑似主板故障
- Node.js简介与架构
- 原生js获取cookie
- 抖音如何开通直播教程
- css实现网页对联广告
- win10网络重置后wlan 不见解法 ,网卡黄色感叹号
- 密码必须符合复杂性要求
- PyCharm的使用
- 4.18号C语言+操作系统。