boost::any实现分析

这里提到的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));
    }





发布了56 篇原创文章 · 获赞 21 · 访问量 26万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览