boost::any实现分析
2013-03-19 17:09
197 查看
这里提到的boost::any,下面来分析一下boost::any的实现。
首先,any类没有用模版参数,这是为什么呢?显而易见,因为any的设计初衷我想就是提供如下的使用方式:
而非
即,提供一种动态的数据类型,并接受单个对象的同时能够获得它的类型
如果用了模版参数变成boost::any<int> any_value(10)这样,那any_value就确定是int类型,并且在使用时还需要传类型作为模版参数。所以,any必须不能是模板类。那么问题来了,如果any不是模板类,它怎么才能泛化的保存各种类型呢?答案就在虚基类placeholder和它的派生模板类holder。
因为any不是模板类不能保存泛型数据,那就需要将原数据用一种容器包起来,然后让any持有一个指针,指向这个容器。那么很明显,这个容器类必须是模板类,因为这样它才能保存泛型数据,而又因为any不是模板类,它的任何数据成员都不能是泛型的,那就需要一个基类,让any持有这个基类的指针,而“容器”从这个基类派生并带模版参数。这样就解决了问题,即让原来需要泛型化存储数据的的any不泛型化,转而定义一种泛型化容器来保存数据,而any自己握住该泛型化容器基类的指针指向这个泛型化的容器。太绕了...绕这么一圈的目的,就是为了开始提到的涉及初衷:提供一种动态的数据类型,并接受单个对象的同时能够获得它的类型。
核心的分析完了,再分析些具体的。
既然需要
那就需要对any的带参构造函数、拷贝构造函数处理成带模版参数的,并重载=操作符(也带模版参数)。这里可以仔细看看重载=操作符里的swap函数,很多重载=操作符的都是采用swap的方式实现赋值的。
再说下从any对象中获取数据的方式
直接将any对象赋给某种类型的对象是不允许的,编不过,因为any对象并没有重载目标对象的操作符(也不可能重载,那么多类型)。因此就需要采用any_cast的方式,当然,还有一个unsafe_any_cast的函数,差别就是any_cast在转换时会进行类型匹配检查,只有类型一致的,才会转,否则抛出异常,而unsafe_any_cast不进行类型匹配检查而直接转。
代码如下:
class any { public: // structors any() : content(0) { } template<typename ValueType> any(const ValueType & value) : content(new holder<ValueType>(value)) { } any(const any & other) : content(other.content ? other.content->clone() : 0) { } ~any() { delete content; } public: // modifiers any & swap(any & rhs) { std::swap(content, rhs.content); return *this; } template<typename ValueType> any & operator=(const ValueType & rhs) { any(rhs).swap(*this); return *this; } any & operator=(any rhs) { rhs.swap(*this); return *this; } public: // queries bool empty() const { return !content; } const std::type_info & type() const { return content ? content->type() : typeid(void); } #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS private: // types #else public: // types (public so any_cast can be non-friend) #endif class placeholder { public: // structors virtual ~placeholder() { } public: // queries virtual const std::type_info & type() const = 0; virtual placeholder * clone() const = 0; }; template<typename ValueType> class holder : public placeholder { public: // structors holder(const ValueType & value) : held(value) { } public: // queries virtual const std::type_info & type() const { return typeid(ValueType); } virtual placeholder * clone() const { return new holder(held); } public: // representation ValueType held; private: // intentionally left unimplemented holder & operator=(const holder &); }; #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS private: // representation template<typename ValueType> friend ValueType * any_cast(any *); template<typename ValueType> friend ValueType * unsafe_any_cast(any *); #else public: // representation (public so any_cast can be non-friend) #endif placeholder * content; };
首先,any类没有用模版参数,这是为什么呢?显而易见,因为any的设计初衷我想就是提供如下的使用方式:
boost::any any_value(10); boost::any any_value1("123");
而非
boost::any<int> any_value(10); boost::any<std::string> any_value1("123");
即,提供一种动态的数据类型,并接受单个对象的同时能够获得它的类型
如果用了模版参数变成boost::any<int> any_value(10)这样,那any_value就确定是int类型,并且在使用时还需要传类型作为模版参数。所以,any必须不能是模板类。那么问题来了,如果any不是模板类,它怎么才能泛化的保存各种类型呢?答案就在虚基类placeholder和它的派生模板类holder。
因为any不是模板类不能保存泛型数据,那就需要将原数据用一种容器包起来,然后让any持有一个指针,指向这个容器。那么很明显,这个容器类必须是模板类,因为这样它才能保存泛型数据,而又因为any不是模板类,它的任何数据成员都不能是泛型的,那就需要一个基类,让any持有这个基类的指针,而“容器”从这个基类派生并带模版参数。这样就解决了问题,即让原来需要泛型化存储数据的的any不泛型化,转而定义一种泛型化容器来保存数据,而any自己握住该泛型化容器基类的指针指向这个泛型化的容器。太绕了...绕这么一圈的目的,就是为了开始提到的涉及初衷:提供一种动态的数据类型,并接受单个对象的同时能够获得它的类型。
核心的分析完了,再分析些具体的。
既然需要
boost::any any_value(10); boost::any any_value1 = "str";
那就需要对any的带参构造函数、拷贝构造函数处理成带模版参数的,并重载=操作符(也带模版参数)。这里可以仔细看看重载=操作符里的swap函数,很多重载=操作符的都是采用swap的方式实现赋值的。
template<typename ValueType> any & operator=(const ValueType & rhs) { any(rhs).swap(*this); return *this; }这里先创建一个临时对象any(rhs),再调用swap进行底层数据交换,注意与*this交换数据的是临时对象,所以rhs的底层数据并未更改,在swap结束后临时对象拿住了*this的底层数据,而这时*this也拿到了临时对象构造时创建的rhs的数据副本。临时对象由于函数结束生命周期也结束而析构掉,则原来*this的底层数据也就没了。这样就实现了将*this原来的底层数据干掉,让*this持有rhs的底层数据的副本。
再说下从any对象中获取数据的方式
int a = 0; boost::any any_value(a); int b = any_value;//这是不允许的 int b = any_cast<int>(any_value);//正确
直接将any对象赋给某种类型的对象是不允许的,编不过,因为any对象并没有重载目标对象的操作符(也不可能重载,那么多类型)。因此就需要采用any_cast的方式,当然,还有一个unsafe_any_cast的函数,差别就是any_cast在转换时会进行类型匹配检查,只有类型一致的,才会转,否则抛出异常,而unsafe_any_cast不进行类型匹配检查而直接转。
代码如下:
class bad_any_cast : public std::bad_cast { public: virtual const char * what() const throw() { return "boost::bad_any_cast: " "failed conversion using boost::any_cast"; } }; template<typename ValueType> ValueType * any_cast(any * operand) { return operand && #ifdef BOOST_AUX_ANY_TYPE_ID_NAME std::strcmp(operand->type().name(), typeid(ValueType).name()) == 0 #else operand->type() == typeid(ValueType) #endif ? &static_cast<any::holder<ValueType> *>(operand->content)->held : 0; } template<typename ValueType> inline const ValueType * any_cast(const any * operand) { return any_cast<ValueType>(const_cast<any *>(operand)); } template<typename ValueType> ValueType any_cast(any & operand) { typedef BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type nonref; #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // If 'nonref' is still reference type, it means the user has not // specialized 'remove_reference'. // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro // to generate specialization of remove_reference for your class // See type traits library documentation for details BOOST_STATIC_ASSERT(!is_reference<nonref>::value); #endif nonref * result = any_cast<nonref>(&operand); if(!result) boost::throw_exception(bad_any_cast()); return *result; } template<typename ValueType> inline ValueType any_cast(const any & operand) { typedef BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type nonref; #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // The comment in the above version of 'any_cast' explains when this // assert is fired and what to do. BOOST_STATIC_ASSERT(!is_reference<nonref>::value); #endif return any_cast<const nonref &>(const_cast<any &>(operand)); } // Note: The "unsafe" versions of any_cast are not part of the // public interface and may be removed at any time. They are // required where we know what type is stored in the any and can't // use typeid() comparison, e.g., when our types may travel across // different shared libraries. template<typename ValueType> inline ValueType * unsafe_any_cast(any * operand) { return &static_cast<any::holder<ValueType> *>(operand->content)->held; } template<typename ValueType> inline const ValueType * unsafe_any_cast(const any * operand) { return unsafe_any_cast<ValueType>(const_cast<any *>(operand)); }
相关文章推荐
- Boost::asio io_service 实现分析
- Boost::asio io_service 实现分析
- 并发编程(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题
- Boost::any分析
- boost::any的简易实现版本
- boost::static_pointer_cast实现分析
- boost 库 enable_shared_from_this 实现原理分析
- 并发编程(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题
- Boost 库 Enable_shared_from_this 实现原理分析
- Boost::asio范例分析 服务端线程池实现
- Boost 库 enable_shared_from_this 实现原理分析
- 【转发】boost::shared_ptr 分析与实现
- boost 库 enable_shared_from_this 实现原理分析
- Boost::any分析
- boost 库 enable_shared_from_this 实现原理分析
- boost any类库的使用和内部实现细节
- Boost::asio io_service 实现分析
- Boost::any分析
- boost 库 enable_shared_from_this 实现原理分析
- boost::shared_ptr 分析与实现