c++ - 由于速度原因使用std vector作为map,靠谱吗?

标签 c++ c++11 vector

<分区>

对于我的嵌入式项目,我使用了 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() 不是最佳选择的另一种情况是,如果您只需要在 vectorend() 处插入值。那么你应该使用 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} 来填充它,然后只更新少数几个非零个案。

关于c++ - 由于速度原因使用std vector作为map,靠谱吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38171911/

相关文章:

c++ - Mac osx c++ .app 找不到文件 fopen()

c++ - C++中的继承和多文件

algorithm - "cut and paste"std::vector 的最后 k 个元素有效吗?

c++ - 如何在具有依赖元素类型的模板类构造函数中初始化 vector

c++ - 分配不同类型的多维 vector

c++函数像printf

c++ - 折叠表达式 () 在哪里?

string - 用同一向量 Rust 中的另一个字符串扩展一个字符串

c++ - Clang 输出错误 "no matching construct for initialization"

c++ - 以下代码对于多线程增量计数器和打印是否是一个好的解决方案?