在地图中存储不同的数据类型 - 类型信息 [英] Store different data types in map - with info on type

查看:161
本文介绍了在地图中存储不同的数据类型 - 类型信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要解析和存储一个(但不是太)复杂的流,并需要存储解析结果不知何故。该流基本上包含 value 的名称 - 值对,对于不同的 name 可能是不同类型的。基本上,我结束了(总是字符串)到< type,value> 的映射。

I need to parse and store a somewhat (but not too) complex stream and need to store the parsed result somehow. The stream essentially contains name-value pairs with values possibly being of different type for different names. Basically, I end up with a map of key (always string) to a pair <type, value>.

我开始用这样的:

typedef enum ValidType {STRING, INT, FLOAT, BINARY} ValidType;
map<string, pair<ValidType, void*>> Data;

但我真的不喜欢 void * 指针。当然,我总是可以将值存储为二进制数据(例如 vector ),在这种情况下 map 将最终成为

However I really dislike void* and storing pointers. Of course, I can always store the value as binary data (vector<char> for example), in which case the map would end up being

map<string, pair<ValidType, vector<char>>> Data;

然而,在这种情况下,我必须解析二进制数据每次需要实际的值,这在性能方面是相当昂贵的。

Yet, in this case I would have to parse the binary data every time I need the actual value, which would be quite expensive in terms of performance.

考虑到我不太担心内存占用(数据量不大),但我担心性能,什么是正确的方式来存储这样的数据?

Considering that I am not too worried about memory footprint (the amount of data is not large), but I am concerned about performance, what would be the right way to store such data?

理想情况下,我想避免使用boost,因为这将增加最终应用程序的大小

Ideally, I'd like to avoid using boost, as that would increase the size of the final app by a factor of 3 if not more and I need to minimise that.

推荐答案

您正在寻找一个歧视的(或标记的) union。

You're looking for a discriminated (or tagged) union.

Boost.Variant就是一个例子,Boost.Any是另一个例子。你确定Boost会增加你的最终应用程序的大小一个因素3?我会认为variant是唯一的,在这种情况下你不需要链接任何库。

Boost.Variant is one example, and Boost.Any is another. Are you so sure Boost will increase your final app size by a factor of 3? I would have thought variant was header-only, in which case you don't need to link any libraries.

如果你真的不能使用Boost,实现一个简单的歧视的联合不是那么难(一般和完全正确的是另一回事),至少你知道现在要搜索。

If you really can't use Boost, implementing a simple discriminated union isn't so hard (a general and fully-correct one is another matter), and at least you know what to search for now.

为了完整性,一个幼稚的歧视联盟可能如下所示:

For completeness, a naive discriminated union might look like:

class DU
{
public:
    enum TypeTag { None, Int, Double };
    class DUTypeError {};
private:
    TypeTag type_;
    union {
        int i;
        double d;
    } data_;

    void typecheck(TypeTag tt) const { if(type_ != tt) throw DUTypeError(); }
public:
    DU() : type_(None) {}
    DU(DU const &other) : type_(other.type_), data_(other.data_) {}
    DU& operator= (DU const &other) {
        type_=other.type_; data_=other.data_; return *this;
    }

    TypeTag type() const { return type_; }
    bool istype(TypeTag tt) const { return type_ == tt; }

#define CONVERSIONS(TYPE, ENUM, MEMBER) \
    explicit DU(TYPE val) : type_(ENUM) { data_.MEMBER = val; } \
    operator TYPE & () { typecheck(ENUM); return data_.MEMBER; } \
    operator TYPE const & () const { typecheck(ENUM); return data_.MEMBER; } \
    DU& operator=(TYPE val) { type_ = ENUM; data_.MEMBER = val; return *this; }

    CONVERSIONS(int, Int, i)
    CONVERSIONS(double, Double, d)
};

现在,有几个缺点:


  • 您不能在联合中存储非POD类型

  • 添加类型表示修改枚举,联合记住要添加新的 CONVERSIONS 行(如果没有宏则更糟)

  • 您不能使用访问者模式(或者,你必须为它编写自己的调度程序),这意味着客户端代码

    • 中的大量switch语句,这些开关中的每一个也可能需要如果您添加类型
    • ,如果您添加类型,则更新
    • 如果您写入了访问者调度,则需要更新

    • you can't store non-POD types in the union
    • adding a type means modifying the enum, and the union, and remembering to add a new CONVERSIONS line (it would be even worse without the macro)
    • you can't use the visitor pattern with this (or, you'd have to write your own dispatcher for it), which means lots of switch statements in the client code
      • every one of these switches may also need updating if you add a type
      • if you did write a visitor dispatch, that needs updating if you add a type, and so may every visitor

      有些问题可以解决,如果你关心他们,但这是更多的工作。因此,我喜欢不重新创造这个特定的车轮,如果它可以避免。

      Some of these issues can be addressed if you care about them, but it's all more work. Hence my preference for not re-inventing this particular wheel if it can be avoided.

      这篇关于在地图中存储不同的数据类型 - 类型信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆