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

boost::any用法示例:

#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,类型转换的功能。

#include <iostream>
#include <list>
#include <cassert>

//自定义的any类
class any
{
public:

    //保存真正数据的接口类
    class placeholder
    {
    public:
        virtual ~placeholder()
        {
        }
    public: 

        virtual const std::type_info & type() const = 0;
        virtual placeholder * clone() const = 0;
    };

    //真正保存和获取数据的类。
    template<typename ValueType>
    class holder : public placeholder
    {
    public:
        holder(const ValueType & value): held(value)
        {
        }

    public: 

        virtual const std::type_info & type() const
        {
            return typeid(ValueType);
        }

        virtual placeholder * clone() const
        {
            return new holder(held);//使用了原型模式
        }

    public: 

        //真正的数据,就保存在这里
        ValueType held;
    };

public:

    any(): content(NULL)
    {
    }

    //模板构造函数,参数可以是任意类型,真正的数据保存在content中
    template<typename ValueType>
    any(const ValueType & value): content(new holder<ValueType>(value))
    {
    }  

    //拷贝构造函数
    any(const any & other)
        : content(other.content ? other.content->clone() : 0)
    {
    }

    //析构函数,删除保存数据的content对象
    ~any()
    {
        if(NULL != content)
            delete content;
    }

private:
    //一个placeholde对象指针,指向其子类folder的一个实现
    // 即content( new holder<ValueType>(value) )语句
    placeholder* content;

    template<typename ValueType> friend ValueType any_cast(const any& operand);
public: 

    //查询真实数据的类型。
    const std::type_info & type() const
    {
        return content ? content->type() : typeid(void);
    }
};

//获取content->helder数据的方法。用来获取真正的数据
template<typename ValueType>
ValueType any_cast(const any& operand)
{
    assert( operand.type() == typeid(ValueType) );
    return static_cast<any::holder<ValueType> *>(operand.content)->held;
}

//下代码是使用示例

typedef std::list<any> list_any;

void fill_list(list_any& la)
{
    la.push_back(10);//存放常数;调用了any的模板构造函数,下同
    la.push_back( std::string("我是string") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组

    char* p = "我是常量区字符串abc";
    la.push_back(p);//可以存放指针,但要注意指针的失效问题
}

//根据类型进行显示
void show_list(list_any& la)
{
    list_any::iterator it;

    for( it = la.begin(); it != la.end(); it++ )
    {    

        if( (*it).type() == typeid(int) )
            std::cout<<any_cast<int>(*it)<<std::endl;
        else if( (*it).type() == typeid(std::string) )
            std::cout<<any_cast<std::string>(*it).c_str()<<std::endl;
        else if( (*it).type() == typeid(char*) )
            std::cout<<any_cast<char*>(*it)<<std::endl;
    }
}

int main()
{
    list_any la;
    fill_list(la);
    show_list(la);

    return 0;
}

参考文献

1)http://www.nohack.cn/code/other/2006-10-05/10230.html

2)boost::any源代码

时间: 2024-10-10 19:04:38

[转] boost::any的用法、优点和缺点以及源代码分析的相关文章

Boost Log 基本用法

Boost Log 基本用法 flyfish 2014-11-5 根据boost提供的代码示例,学习Boost Log 的基本用法 前提 boost版本boost_1_56_0 示例代码文件夹 boost_1_56_0\libs\log\example\basic_usage 使用的单词很形象,整个过程就像流水一样 假设要输出的日志比作水 水                     (Hello, World!) 水槽                 (sink) 流向哪里        (co

boost的posix_time用法详解01

// boost_time.cpp : 定义控制台应用程序的入口点. //made by davidsu33 //2014-5-11 //the usage of posix_time #include "stdafx.h" #include <boost/date_time/posix_time/posix_time.hpp> #include <iostream> #include <cassert> using namespace std; #

转:RTMPDump源代码分析

0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://.也提供 Android 版本. 最近研究了一下它内部函数调用的关系. 下面列出几个主要的函数的调用关系. RTMPDump用于下载RTMP流媒体的函数Download: 用于建立网络连接(NetConnect)的函数Connect: 用于建立网络流(NetStream)的函数 rtmpdump源代码

Cocos2d-X3.0 刨根问底(九)----- 场景切换(TransitionScene)源代码分析

上一章我们分析了Scene与Layer相关类的源代码,对Cocos2d-x的场景有了初步了解,这章我们来分析一下场景变换TransitionScene源代码. 直接看TransitionScene的定义 class CC_DLL TransitionScene : public Scene { public: /** Orientation Type used by some transitions */ enum class Orientation { /// An horizontal or

FreeBSD 5.0中强制访问控制机制的使用与源代码分析【转】

本文主要讲述FreeBSD 5.0操作系统中新增的重要安全机制,即强制访问控制机制(MAC)的使用与源代码分析,主要包括强制访问控制框架及多级安全(MLS)策略两部分内容.这一部分讲述要将MAC框架与MLS策略用起来,应该做的一些工作,以及如何有效使用它们的问题. ? 强制访问控制(英文缩写MAC)是实现操作系统安全的一个重要的方法,现在几乎所有的安全操作系统都采用强制访问控制作为其核心安全机制之一.强制访问控制是对操作系统的各种客体(如文件.socket.系统FIFO.SCD.IPC等)进行细

JAVA随笔篇一(Timer源代码分析和scheduleAtFixedRate的使用)

写完了基础篇,想了非常久要不要去写进阶篇.去写JSP等等的用法.最后决定先不去写.由于自己并非JAVA方面的大牛.眼下也在边做边学,所以决定先将自己不懂的拿出来学并记下来. Timer是Java自带的java.util.Timer类,通过调度一个java.util.TimerTask任务.这样的方式能够让程序依照某一个频度运行. 1.Timer类的源代码分析: public class Timer { /** * The timer task queue. This data structure

转:ffdshow 源代码分析

ffdshow神奇的功能:视频播放时显示运动矢量和QP FFDShow可以称得上是全能的解码.编码器.最初FFDShow只是mpeg视频解码器,不过现在他能做到的远不止于此.它能够解码的视频格式已经远远超出了mpeg4的范围,包括indeo video,WMV,mpeg2等等.同时,它也提供了丰富的加工处理选项,可以锐化画面,调节画面的亮度等等.不止是视频,FFDShow现在同样可以解码音频,AC3.MP3等音频格式都可支持.并且可以外挂winamp 的DSP插件,来改善听觉效果.可以说现在的F

Android应用程序绑定服务(bindService)的过程源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6745181 Android应用程序组件Service与Activity一样,既可以在新的进程中启动,也可以在应用程序进程内部 启动:前面我们已经分析了在新的进程中启动Service的过程,本文将要介绍在应用程序内部绑定Service的过程,这是一种在应用程序进程内部启动 Service的方法. 在前面一篇文章Android进程间通信(IPC)机

Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6664554 在上一文章Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划中, 我们简要介绍了Android系统的匿名共享内存机制,其中,简要提到了它具有辅助内存管理系统来有效地管理内存的特点,但是没有进一步去了解它是如何实 现的.在本文中,我们将通过分析Android系统的匿名共享内存