对于我的嵌入式项目,我使用了 unordered_map
以十六进制值作为键和 uint32_t
作为值(value)观。然而,它们非常的成本很高,而且一些基准测试表明使用 vector 要快得多。 (在仅持续 50us 的中断期间,10us 与 1us)
由于键仅用于对值进行排序和提高可读性,因此除了易用性之外,我没有发现 unordered_map
有任何好处。 .
但是,我想知道这样做是否靠谱。从某种意义上说,在插入操作以将 2 个 vector 合并在一起之后,我会丢失数据和/或排序吗?我的 vector 看起来像这样:std::vector<uint32_t>
索引总是不同的
使用 vector 的另一个缺点是我必须用所需的位置预先初始化 vector ,这限制了这种方法的灵 active 。
// The PARAM_ values are indeces in HEX
dataMapA.insert(dataMapA.begin() + PARAM_MOTOR_ANGLE, 0);
dataMapA.insert(dataMapA.begin() + PARAM_MOTOR_VELOCITY, 0);
dataMapA.insert(dataMapA.begin() + PARAM_JOINT_ANGLE, 0);
dataMapA.insert(dataMapA.begin() + PARAM_SPRING_ANGLE, 0);
如果我不执行上述操作,我将无法存储任何值。
以下可能是一个解决方案,但在定义为私有(private)/公共(public)成员时似乎不起作用。 Eclipse 抛出语法错误。
std::vector<uint32_t> dataMapA(10);
所以我想这个问题可以概括为如何将 vector 用作键值查找表并使其尽可能高效,同时仍保持一定的可读性。
问题
// The PARAM_ values are indeces in HEX
dataMapA.insert(dataMapA.begin() + PARAM_MOTOR_ANGLE, 0);
dataMapA.insert(dataMapA.begin() + PARAM_MOTOR_VELOCITY, 0);
dataMapA.insert(dataMapA.begin() + PARAM_JOINT_ANGLE, 0);
dataMapA.insert(dataMapA.begin() + PARAM_SPRING_ANGLE, 0);
这绝对不是在给定索引处设置值的方法。它可能适用于简单的情况,但如果你 insert()
不是严格按升序排列,你就有麻烦了,因为每次调用 insert(blah, n)
将位于 n
和更大位置的所有元素右移 1,并将新元素放在 n
处。因此,在这种情况下,您的值最终会从您尝试存储它们的“索引”中偏移。
insert()
(虽然在某些情况下您可以改变它来完成其他方法的工作)实际上是用于在旧值之中或之前添加新值,包括为此需要采取的任何行动。
无论如何,如果您在插入 vector
之前没有resize()
d,那就是 UB。传递的迭代器需要对当前的 size()
有效。
如果这些事情中的任何一个出了问题...我希望我最终不会乘坐任何使用此 MOTOR
的车辆。
解决方案
If I don't do the above, I can not store any values.
是的,你可以。调用resize(n)
分配并默认构造有效元素,然后使用operator[]
访问他们。 这就是您索引到连续容器的方式。把它想象成一个数组。对于 vector
,它是 。如果你想要临时边界检查,请使用你的标准库调试版本的 operator[]
,或者如果你想减慢你的程序直到你花费大量的时间,请使用 .at(index)
进行查找和替换的能量。
重要的一点:危险的类似名称 reserve()
仅保留内存,即增加 capacity()
;它不会增加 vector 的size()
,因此不能使用[size() - 1]
之外的假想新索引(是UB),直到通过适当的方法之一在那里构造了一个元素。正如我将在下面概述的那样,reserve()
非常好……只是不适用于 operator[]
。
备选方案
insert()
不是最佳选择的另一种情况是,如果您只需要在 vector
的 end()
处插入值。那么你应该使用 emplace_back(forwarded, constructor, arguments)
或 push_back(thingToCopy)
。这些可以与 reserve()
结合使用,例如如果您知道“我将有 50 个元素但需要在循环中计算它们”,或者您现在只想过度分配以减少以后重新分配的次数。
最后,如果您的 vector
始终具有相同的大小...为什么它是 vector
?只需使用具有编译时大小的数组。以下是两者的示例:
// if size is not known at compile time:
std::vector<std::uint32_t> dataMapA;
// Calculate dataMapSize at runtime, then
a.resize(dataMapSize);
// if size is known at compile time:
std::uint32_t dataMapA[DATAMAPSIZE]; // DATAMAPSIZE must be constexpr
// or
std::array<std::uint32_t, DATAMAPSIZE>; // if you want its added features, e.g. .at(), copyability
// then in either case:
dataMapA[PARAM_MOTOR_ANGLE] = 0;
dataMapA[PARAM_MOTOR_VELOCITY] = 0;
dataMapA[PARAM_JOINT_ANGLE] = 0;
dataMapA[PARAM_SPRING_ANGLE] = 0;
// and std::array and vector offer .at(n) for bounds-checked indexing
当然,如果您的大部分数组元素都是0
,那么您可以构造{0}
来填充它,然后只更新少数几个非零个案。