boost::any实现分析

来源:互联网 发布:java 类对象降序 编辑:程序博客网 时间:2024/06/07 16:17

这里提到的boost::any,下面来分析一下boost::any的实现。

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));    }





原创粉丝点击