<转>boost::any的用法、优点和缺点以及源代码分析

摘要:
这是boost::any的优点之一。而前面提到的mylist只能存放BaseClass类指针以及其继承类的指针。分析并模仿boost::any:读了一下boost::any的源代码,并模仿一下其实现,下面是代码。
01.#include <iostream>
02.#include <list>
03.#include <boost/any.hpp>
04.
05.typedef std::list<boost::any> list_any;
06.
07.//关键部分:可以存放任意类型的对象
08.void fill_list(list_any& la)
09.{
10. la.push_back(10);//存放常数
11. la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组
12.}
13.
14.//根据类型进行显示
15.void show_list(list_any& la)
16.{
17. list_any::iterator it;
18. boost::any anyone;
19.
20. for( it = la.begin(); it != la.end(); it++ )
21. {
22. anyone = *it;
23.
24. if( anyone.type() == typeid(int) )
25. std::cout<<boost::any_cast<int>(*it)<<std::endl;
26. else if( anyone.type() == typeid(std::string) )
27. std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;
28. }
29.}
30.
31.int main()
32.{
33. list_any la;
34. fill_list(la);
35. show_list(la);
36.
37. return 0;
38.}
#include <iostream>
#include <list>
#include <boost/any.hpp>
typedef std::list<boost::any> list_any;
//关键部分:可以存放任意类型的对象
void fill_list(list_any& la)
{
la.push_back(10);//存放常数
la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组
}
//根据类型进行显示
void show_list(list_any& la)
{
list_any::iterator it;
boost::any anyone;
for( it = la.begin(); it != la.end(); it++ )
{
anyone = *it;
if( anyone.type() == typeid(int) )
std::cout<<boost::any_cast<int>(*it)<<std::endl;
else if( anyone.type() == typeid(std::string) )
std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;
}
}
int main()
{
list_any la;
fill_list(la);
show_list(la);
return 0;
}
boost::any的优点:
对设计模式理解的朋友都会知道合成模式。因为多态只有在使用指针或引用的情况下才能显现,所以std容器中只能存放指针或引用(但实际上只能存放指针,无法存放引用,这个好像是c++的不足吧)。如:
std::list<BaseClass*> mylist;
这样,我们就要对指针所指向内容的生存周期操心(可能需要程序员适时删除申请的内存;但是由于存放指针,插入/删除的效率高),而使用boost::any就可能避免这种情况,因为我们可以存放类型本身(当然存放指针也可以)。这是boost::any的优点之一。
boost::any另一个优点是可以存放任何类型。而前面提到的mylist只能存放BaseClass类指针以及其继承类的指针。
boost::any的缺点:
由于boost::any可以存放任何类型,自然它用不了多态特性,没有统一的接口,所以在获取容器中的元素时需要实现判别元素的真正类型,这增加了程序员的负担。与面向对象编程思想有些矛盾,但整个标准c++模板库何尝不是如此,用那些牛人的话来说,是“有益补充”。
总之,有利必有弊,没有十全十美的。
分析并模仿boost::any:
读了一下boost::any的源代码,并模仿一下其实现(相当一部分时拷贝原代码),下面是代码(只包含必要功能)。
实现any的功能主要由三部分组成:
1)any类
2)真正保存数据的holder类及其基类placeholder
3)获取真正数据的模板函数any_cast,类型转换的功能。
view plaincopy to clipboardprint?
01.#include <iostream>
02.#include <list>
03.#include <cassert>
04.
05.//自定义的any类
06.class any
07.{
08.public:
09.
10. //保存真正数据的接口类
11. class placeholder
12. {
13. public:
14. virtual ~placeholder()
15. {
16. }
17. public:
18.
19. virtual const std::type_info & type() const = 0;
20. virtual placeholder * clone() const = 0;
21. };
22.
23. //真正保存和获取数据的类。
24. template<typename ValueType>
25. class holder : public placeholder
26. {
27. public:
28. holder(const ValueType & value): held(value)
29. {
30. }
31.
32. public:
33.
34. virtual const std::type_info & type() const
35. {
36. return typeid(ValueType);
37. }
38.
39. virtual placeholder * clone() const
40. {
41. return new holder(held);//使用了原型模式
42. }
43.
44. public:
45.
46. //真正的数据,就保存在这里
47. ValueType held;
48. };
49.
50.public:
51.
52. any(): content(NULL)
53. {
54. }
55.
56. //模板构造函数,参数可以是任意类型,真正的数据保存在content中
57. template<typename ValueType>
58. any(const ValueType & value): content(new holder<ValueType>(value))
59. {
60. }
61.
62. //拷贝构造函数
63. any(const any & other)
64. : content(other.content ? other.content->clone() : 0)
65. {
66. }
67.
68. //析构函数,删除保存数据的content对象
69. ~any()
70. {
71. if(NULL != content)
72. delete content;
73. }
74.
75.private:
76. //一个placeholde对象指针,指向其子类folder的一个实现
77. // 即content( new holder<ValueType>(value) )语句
78. placeholder* content;
79.
80. template<typename ValueType> friend ValueType any_cast(const any& operand);
81.public:
82.
83. //查询真实数据的类型。
84. const std::type_info & type() const
85. {
86. return content ? content->type() : typeid(void);
87. }
88.};
89.
90.
91.//获取content->helder数据的方法。用来获取真正的数据
92.template<typename ValueType>
93.ValueType any_cast(const any& operand)
94.{
95. assert( operand.type() == typeid(ValueType) );
96. return static_cast<any::holder<ValueType> *>(operand.content)->held;
97.}
98.
99.//下代码是使用示例
100.
101.typedef std::list<any> list_any;
102.
103.void fill_list(list_any& la)
104.{
105. la.push_back(10);//存放常数;调用了any的模板构造函数,下同
106. la.push_back( std::string("我是string") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组
107.
108. char* p = "我是常量区字符串abc";
109. la.push_back(p);//可以存放指针,但要注意指针的失效问题
110.}
111.
112.//根据类型进行显示
113.void show_list(list_any& la)
114.{
115. list_any::iterator it;
116.
117. for( it = la.begin(); it != la.end(); it++ )
118. {
119.
120. if( (*it).type() == typeid(int) )
121. std::cout<<any_cast<int>(*it)<<std::endl;
122. else if( (*it).type() == typeid(std::string) )
123. std::cout<<any_cast<std::string>(*it).c_str()<<std::endl;
124. else if( (*it).type() == typeid(char*) )
125. std::cout<<any_cast<char*>(*it)<<std::endl;
126. }
127.}
128.
129.int main()
130.{
131. list_any la;
132. fill_list(la);
133. show_list(la);
134.
135. return 0;
136.}
boost::any是一个很有趣的类,刚刚开始我还以为其就是一个variant类型,
能够将任意类型值保存进去,能够以任意类型值读出来,不过我错了:(
boost::any的作者认为,所谓generictype有三个层面的解释方法:
1.类似variant类型那样任意进行类型转换,可以保存一个(int)5进去,
读一个(string)"5"出来。Win下面的VARIANT类型是以一个巨大的
union实现的类似功能,使用灵活但效率较低
2.区别对待包含值的类型,保存一个(int)5进去,不会被隐式转换为
(string)'5'或者(double)5.0,这样效率较高且类型安全,
不必担心ambiguousconversions
3.对包含值类型不加区别,例如把所有保存的值强制转换为void*保存
读取时再有程序员判断其类型。这样效率虽最高但无法保证类型安全
boost::any就选择了第二层面的设计思路,它允许用户将任意类型值保存
进一个any类型变量,但内部并不改变值的类型,并提供方法让用户在使用时
主动/被动进行类型判断。
在实现方面,boost::any使用两层内部类placeholder和holder保存
实际类型的值。类placeholder只是一个接口,模板类holder是特定类型
的实现。其中type()方法获取实际值类型,即typeid(ValueType);
clone()方法获取值的拷贝returnnewholder(held);
virtualconststd::type_info&type()const
virtualplaceholder*clone()const
其值的类型信息不象Win的VARIANT那样以专门的字段保存,
而是通过模板参数形式静态保存。这样效率更高(仅在编译期),
通用性更强(任何类型都可以,真正any)但灵活性不如VARIANT
在进行拷贝构造/赋值/swap时,都直接将整个placeholder换掉,
这样可以保证值类型的延续性。
在使用方面,提供了主动/被动进行类型检测的方法。
可以使用any::type()方法主动检测值类型
boolis_int(constboost::any&operand)
{
returnoperand.type()==typeid(int);
}
也可以通过any_cast函数被动进行检测。此函数与C++中的*_cast
系列关键字有相同的语法规范,尝试进行类型转换,如类型不匹配则对
指针转换返回NULL,对引用转换抛出boost::bad_any_cast异常
boost::anystr=string("12345");
try
{
cout<<boost::any_cast<int>(str)<<endl;
}
catch(boost::bad_any_caste)
{
cerr<<e.what()<<endl;
}
在应用方面,any类型适合于类型不同但使用相关的值。如C++的...
形式的函数参数本事不是类型安全的,可以通过vector<any>改造之
然后在使用时检测类型是否匹配,如可改造printf为
voidsafe_printf(constchar*format,constvector<any>&params)
{
intindex=0;
for(constchar*pch=format;*pch;pch++)
{
switch(*pch)
{
case'%':
{
switch(*++pch)
{
case'i':
case'd':
{
if(params[index].type()==typeid(int)||
params[index].type()==typeid(short))
{
...
}
else
throw...
}
}
}
case'\':
{
...
}
default:
{
putchar(*pch);
}
}
}
}
附:boost::any.hpp
#ifndefBOOST_ANY_INCLUDED
#defineBOOST_ANY_INCLUDED
//what:varianttypeboost::any
//who:contributedbyKevlinHenney,
//withfeaturescontributedandbugsfoundby
//EdBrey,MarkRodgers,PeterDimov,andJamesCurran
//when:July2001
//where:testedwithBCC5.5,MSVC6.0,andg++2.95
#include<algorithm>
#include<typeinfo>
#include"boost/config.hpp"
namespaceboost
{
classany
{
public://structors
any()
:content(0)
{
}
template<typenameValueType>
any(constValueType&value)
:content(newholder<ValueType>(value))
{
}
any(constany&other)
:content(other.content?other.content->clone():0)
{
}
~any()
{
deletecontent;
}
public://modifiers
any&swap(any&rhs)
{
std::swap(content,rhs.content);
return*this;
}
template<typenameValueType>
any&operator=(constValueType&rhs)
{
any(rhs).swap(*this);
return*this;
}
any&operator=(constany&rhs)
{
any(rhs).swap(*this);
return*this;
}
public://queries
boolempty()const
{
return!content;
}
conststd::type_info&type()const
{
returncontent?content->type():typeid(void);
}
#ifndefBOOST_NO_MEMBER_TEMPLATE_FRIENDS
private://types
#else
public://types(publicsoany_castcanbenon-friend)
#endif
classplaceholder
{
public://structors
virtual~placeholder()
{
}
public://queries
virtualconststd::type_info&type()const=0;
virtualplaceholder*clone()const=0;
};
template<typenameValueType>
classholder:publicplaceholder
{
public://structors
holder(constValueType&value)
:held(value)
{
}
public://queries
virtualconststd::type_info&type()const
{
returntypeid(ValueType);
}
virtualplaceholder*clone()const
{
returnnewholder(held);
}
public://representation
ValueTypeheld;
};
#ifndefBOOST_NO_MEMBER_TEMPLATE_FRIENDS
private://representation
template<typenameValueType>
friendValueType*any_cast(any*);
#else
public://representation(publicsoany_castcanbenon-friend)
#endif
placeholder*content;
};
classbad_any_cast:publicstd::bad_cast
{
public:
virtualconstchar*what()constthrow()
{
return"boost::bad_any_cast:"
"failedconversionusingboost::any_cast";
}
};
template<typenameValueType>
ValueType*any_cast(any*operand)
{
returnoperand&&operand->type()==typeid(ValueType)
?&static_cast<any::holder<ValueType>*>(operand->content)->held
:0;
}
template<typenameValueType>
constValueType*any_cast(constany*operand)
{
returnany_cast<ValueType>(const_cast<any*>(operand));
}
template<typenameValueType>
ValueTypeany_cast(constany&operand)
{
constValueType*result=any_cast<ValueType>(&operand);
if(!result)
throwbad_any_cast();
return*result;
}
}
//CopyrightKevlinHenney,2000,2001,2002.Allrightsreserved.
//
//Permissiontouse,copy,modify,anddistributethissoftwareforany
//purposeisherebygrantedwithoutfee,providedthatthiscopyrightand
//permissionsnoticeappearinallcopiesandderivatives.
//
//Thissoftwareisprovided"asis"withoutexpressorimpliedwarranty.
#endif

免责声明:文章转载自《&amp;lt;转&amp;gt;boost::any的用法、优点和缺点以及源代码分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇编程王道,唯“慢”不破6.1 MSI/MSI-X Capability结构 分类: 浅谈PCI-E 2013-07-22 16:28 312人阅读 评论(0) 收藏下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Delphi Math单元函数

  **************************数学单元*********************************Delphi / Kylix 跨平台运行时(Runtime)库Copyright (c) 1996, 2001 Borland 软件**********************************************...

虚表和虚表指针

  编译器:VS2015 0x01 基础概念   首先还是简单重复一下基础概念。   C++的多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。    1、多态性     指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。     a...

JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--实现

先学习下new操作符吧 new关键字调用函数的心路历程: 1.创建一个新对象 2.将函数的作用域赋给新对象(this就指向这个对象) 3.执行函数中的代码 4.返回这个对象 根据这个的思路,来实现一个简单的new操作吧,代码演示: 1 function myNew(Func, ...args) { 2 if (typeof Func !== 'fu...

Qt 访问网络

一、前言 Qt 中访问网络使用 QNetworkAccessManager,它的 API 是异步的,这样在访问网络的时候不需要启动一个线程,在线程里执行请求的代码。(但这一点在有时候需要阻塞时就是个麻烦了) 需要注意一点的是,请求响应的对象 QNetworkReply 需要我们自己手动的删除,一般都会在 QNetworkAccessManager::fin...

IOS基础之 (十) 内存管理

一 基本原理 1.什么是内存管理 移动设备的内存有限,每个app所能占用的内存是有限制的。 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象,变量。 管理范围:任何继承了NSObject,对其他基本数据类型(int, char, float, double,struct,enum等)无效。...

从零开始的野路子React/Node(9)Antd + multer实现文件上传

最近心血来潮,打算自己捣腾个web app来练练手(虽然大概率会半路弃坑……),其中有一部分是关于文件上传的,在实现的过程中遇到了一些坑,于是打算把血泪教训都记录下来。 前端的部分采用了Antd,不得不说真是香,至少比我司内部的前端库香了1000倍……事半功倍。后端部分则主要通过multer来实现,目测应该是一种比较通用的做法? 1、捯饬前端 首先我们新建...