[英]std::map<> or std::vector<> when dealing with large sets of flags?
I am working on a compiler and have a large set of flags. 我正在使用编译器,并且有大量的标志。 In most cases, my nodes will receive a very small number of flags (about 12 for the largest), but the total number of flags is rather large (over 50.) All the flags are integers defined in an enum: 在大多数情况下,我的节点将收到很少的标志(最大的大约12个),但是标志的总数却很大(超过50个。)所有标志都是枚举中定义的整数:
enum flags_t
{
FLAG_ONE,
FLAG_TWO,
FLAG_THREE,
[...]
MAX_FLAG
};
I am thinking that using an std::map<flags_t, bool>
makes more sense because most of my nodes are likely to use 0, 1, or 2 flags and the number of nodes is really large (it can easily become tenth of thousands.) 我认为使用std::map<flags_t, bool>
更有意义,因为我的大多数节点都可能使用0、1或2个标志,并且节点的数量确实很大(很容易变成万分之一)
// with a map we have to check the existing on a get to avoid creating
// useless entries in the map
bool node::get_flag(flags_t const f)
{
flag_iterator it(f_flags.find(f));
return it == f_flags.end() ? false : *it;
}
void node::set_flag(flags_t const f, bool const value)
{
f_flags[f] = value;
}
But I'm wondering whether std::vector<bool>
would not actually end up being more effective? 但是我想知道std::vector<bool>
是否最终不会更有效? Although at first sight this looks good: 虽然乍看之下看起来不错:
bool node::get_flag(flags_t const f)
{
return f_flags[f];
}
void node::set_flag(flags_t const f, bool const value)
{
f_flags[f] = value;
}
The vector needs to be allocated (ie sized properly) on initialization or the get_flag() functions needs to test whether f is part of the vector: 必须在初始化时分配向量(即,适当调整大小),或者get_flag()函数需要测试f是否为向量的一部分:
bool node::get_flag(flags_t const f)
{
return f >= f_flags.size() ? false : f_flags[f];
}
The problem I can see with a resize() call is that we would allocate / free memory all the time, even if we end up never actually using the vector (most nodes don't need any flags!) So testing the limit when we do a get is probably a good trade off, but we also need to make sure that the vector is large enough on the set_flag() call... (in which case we'd probably allocate the whole set of flags at once to avoid reallocations.) 我可以通过resize()调用看到的问题是,即使我们最终从未真正使用过向量(大多数节点不需要任何标志!),我们也将一直分配/释放内存(因此,在测试限制时)进行获取可能是一个不错的权衡,但我们还需要确保向量在set_flag()调用中足够大...(在这种情况下,我们可能会立即分配整个标志集,以避免重新分配。)
bool node::set_flag(flags_t const f, bool const value)
{
if(MAX_FLAG > f_flags.size())
{
f_flags.resize(MAX_FLAG);
}
f_flags[f] = value;
}
So... would std::vector
or std::map
be better? 那么... std::vector
或std::map
会更好吗? Or would possibly std::set
be even better? 还是可能std::set
更好? (I have not used std::set before...) (我还没有使用过std :: set ...)
Both std::set
and std::map
are a suboptimal choice for flags because they allocate storage dynamically, causing unnecessary fragmentation. std::set
和std::map
都是标志的次佳选择,因为它们动态分配存储空间,从而导致不必要的碎片。
A simple way to represent flags is by storing them in an integral type. 表示标志的一种简单方法是将它们存储为整数类型。 An unsigned 64-bit type will provide room for 64 flags. 无符号的64位类型将为64个标志提供空间。 This will be both space-efficient and CPU-efficient, and idiomatic C++ to boot. 这将既节省空间又节省CPU,并且会启动惯用的C ++。 For example: 例如:
enum flag_code
{
FLAG_ONE = 1ULL << 0,
FLAG_TWO = 1ULL << 1,
FLAG_THREE = 1ULL << 2,
[...]
};
typedef uint64_t flags_t;
void node::set_flag(flag_code f, bool value)
{
if (value)
f_flags |= f;
else
f_flags &= ~f;
}
bool node::get_flag(flag_code f)
{
return bool(f_flags & f);
}
If more than 64 flags are needed, the bit manipulation is best left expressed with std::bitset
, which also offers array-like access to individual bits of the underlying value: 如果需要超过64个标志,则最好用std::bitset
表示位操作,该操作还提供对基础值的各个位的类似数组的访问:
enum flag_code
{
FLAG_ONE,
FLAG_TWO,
FLAG_THREE,
[...]
MAX_FLAG
};
typedef std::bitset<MAX_FLAG - 1> flags_t;
void node::set_flag(flag_code f, bool value)
{
f_flags[f] = value;
}
bool node::get_flag(flag_code f)
{
return f_flags[f];
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.