C++ 标准::地图<&燃气轮机;或std::vector<&燃气轮机;当处理大量的旗帜时?
我正在编写一个编译器,有一大组标志。在大多数情况下,我的节点将接收非常少的标志(最大的大约12个),但标志的总数相当大(超过50个)。所有标志都是枚举中定义的整数:C++ 标准::地图<&燃气轮机;或std::vector<&燃气轮机;当处理大量的旗帜时?,c++,vector,map,C++,Vector,Map,我正在编写一个编译器,有一大组标志。在大多数情况下,我的节点将接收非常少的标志(最大的大约12个),但标志的总数相当大(超过50个)。所有标志都是枚举中定义的整数: enum flags_t { FLAG_ONE, FLAG_TWO, FLAG_THREE, [...] MAX_FLAG }; 我认为使用std::map更有意义,因为我的大多数节点都可能使用0、1或2个标志,并且节点的数量非常大(很容易变成千分之一) 但我想知道std::vector是否
enum flags_t
{
FLAG_ONE,
FLAG_TWO,
FLAG_THREE,
[...]
MAX_FLAG
};
我认为使用std::map
更有意义,因为我的大多数节点都可能使用0、1或2个标志,并且节点的数量非常大(很容易变成千分之一)
但我想知道std::vector
是否真的会更有效?虽然乍一看这看起来不错:
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;
}
需要在初始化时分配向量(即大小适当),或者get_flag()函数需要测试f是否是向量的一部分:
bool node::get_flag(flags_t const f)
{
return f >= f_flags.size() ? false : f_flags[f];
}
我在resize()调用中看到的问题是,我们会一直分配/释放内存,即使我们最终从未实际使用过向量(大多数节点不需要任何标志!),因此在执行get时测试限制可能是一个很好的折衷,但我们还需要确保set_flag()调用中的向量足够大。。。(在这种情况下,我们可能会一次分配整个标志集,以避免重新分配。)
所以。。。
std::vector
或std::map
会更好吗?或者std::set
会更好吗?(我以前没有使用过std::set…对于标志,std::set
和std::map
都是次优选择,因为它们动态分配存储,导致不必要的碎片
表示标志的一种简单方法是将它们存储在整数类型中。未签名的64位类型将为64个标志提供空间。这将是空间效率和CPU效率,和习惯性的C++引导。例如:
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);
}
std::set
和std::map
都是次优的标志选择,因为它们动态分配存储,导致不必要的碎片
表示标志的一种简单方法是将它们存储在整数类型中。未签名的64位类型将为64个标志提供空间。这将是空间效率和CPU效率,和习惯性的C++引导。例如:
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);
}
使用位的好处是可以使用逐位操作一次检查所有标志。std::vector?=>标准::bitset@smoothware嗯,他们每个布尔至少使用一个比特。我在想象一些C风格的东西。类似于第一个答案。使用位的好处是可以使用逐位操作一次检查所有标志。std::vector?=>标准::bitset@smoothware嗯,他们每个布尔至少使用一个比特。我在想象一些C风格的东西。类似于第一个答案。我有超过64位,尽管我可以对它们进行分组,而且每个组甚至没有超过16位(尽管这可能会随着时间的推移而增加),出于安全原因(即避免bug),我不希望有任何重叠。这样,如果我检查了错误的标志,我会得到一个错误,而不是一些与软件预期功能无关的随机结果。但是位集可能是最好的解决方案。@Alexiswillke您的问题指出位的总数“超过50”,这给人的印象是低于64位。我现在更新了答案。你是对的!我不知道确切的数字,但可能会超过64。我正在考虑将标志和属性(也是标志)组合在一个集合中,这意味着我将讨论64。感谢您的更新,这将帮助我,因为我以前没有使用过
std::bitset
。我有超过64位,尽管我可以对它们进行分组,每个组甚至没有超过16位(尽管这可能会随着时间的推移而增加),出于安全原因(即,为了避免bug),我不希望有任何重叠。这样,如果我检查了错误的标志,我会得到一个错误,而不是一些与软件预期功能无关的随机结果。但是位集可能是最好的解决方案。@Alexiswillke您的问题指出位的总数“超过50”,这给人的印象是低于64位。我现在更新了答案。你是对的!我不知道确切的数字,但可能会超过64。我正在考虑将标志和属性(也是标志)组合在一个集合中,这意味着我将讨论64。感谢您的更新,这将帮助我,因为我以前没有使用过std::bitset
。
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);
}
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];
}