【问题标题】:C++ map really slow?C++ 映射真的很慢吗?
【发布时间】:2009-11-06 11:44:49
【问题描述】:

我为游戏制作者创建了一个 dll。 dll 的数组真的很慢,所以在询问了一下后,我了解到我可以在 c++ 中使用地图并制作一个 dll。

无论如何,我不能代表我需要存储在 3d 数组中的内容: 信息[id][编号][编号] id 对应于对象 id。第一个数字字段的范围为 0 - 3,每个数字代表不同的设置。第二个数字字段表示数字字段 1 中设置的值。 所以..

information[101][1][4]; 
information[101][2][4]; 
information[101][3][4]; 

这将转换为“ID 为 101 的对象在设置 1、2 和 3 中的值为 4”。 我这样做是为了尝试用地图复制它:

//declared as a class member
map<double,  map<int, double>*> objIdMap;

///// lower down the page, in some function
map<int, double> objSettingsMap;
objSettingsMap[1] = 4;
objSettingsMap[2] = 4;
objSettingsMap[3] = 4;
map<int, double>* temp = &objSettingsMap;
objIdMap[id] = temp;

所以第一个map,objIdMap存储id作为key,一个指向另一个map的指针,存储代表设置的数字作为key,设置的值作为value。

但是,这是针对游戏的,因此可能需要存储具有自己 id 和设置的新对象(有时每隔几秒就有一百个左右的新对象),而现有对象需要不断地检索每个对象的值游戏的步骤。地图不能处理这个吗?我与游戏制造商的阵列有一个非常相似的事情,它工作得很好。

【问题讨论】:

  • 您显然不了解维度和值之间的区别。 “id 为 101 的对象的值为 4 用于设置 1”转换为 information[101][1] = 4;
  • 您几乎肯定不想使用 double 作为地图的键 - 浮点错误会对检索项目所需的比较造成严重破坏。
  • 可能。浮点比较是确定性的。 objIdMap[1.0]objIdMap[1.0]objIdMap[0.5+0.5] 完全相同,但可能不是objIdMap[(1.0/3.0)*3.0]

标签: c++ dll maps


【解决方案1】:

不要使用双精度作为映射的键。 如果您想比较两个双精度数,请尝试使用floating point comparison function

【讨论】:

  • 为什么不呢?稍微解释一下,也许有一些参考资料会有所帮助。
  • 在许多情况下,如果获取它们的操作不同,或者即使操作相同,FPU 可能有比双精度更多的位(当前的英特尔编译器有 80 位寄存器用于 64 位双精度),然后将转储到内存的值与仍在寄存器中的值进行比较将产生错误。
  • 解释和更多讨论在这里:cygnus-software.com/papers/comparingfloats/comparingfloats.htm您还应该通过搜索stackoverflow找到更多信息
  • @Dominic:双打是 64 位的,你不太可能真的需要这么宽的命名空间。最后,双打也是不精确的,如果它们是计算的结果,它们最终可能与以前的计算不同。在某些情况下,双重比较也相当慢,并且必须等待数学协处理器完成它正在做的事情。
【解决方案2】:

1) 你的代码有问题:你存储了一个指向本地对象objSettingsMap 的指针,一旦超出范围就会被销毁。您必须存储地图 obj,而不是指向它的指针,因此本地地图将被复制到此对象中。

2) 地图可以变得任意大(我有数百万个条目的地图)。如果您需要速度,请尝试 hash_maps(C++0x 的一部分,但也可以从其他来源获得),它的速度要快得多。但是每秒添加数百个条目应该不是问题。但在担心执行速度之前,您应该始终使用分析器。

3) 我不确定您的嵌套结构是否必须是地图。根据您拥有的设置数量以及它们可能具有的值,结构或位域或向量可能更准确。

【讨论】:

  • 现在我有“map*> objIdMap;”。我应该将什么放入 value 字段而不是 map* ?它似乎不喜欢“map>”
  • 地图类型应该是map> objIdMap;确保在两个“> >”之间保留一个空格。否则它变成移位运算符“>>”。
  • 喜欢它。现在效果很好。呸,我好害怕...... :D 谢谢
  • !!!当心双打,他们咬人,他们咬得很紧。您应始终避免直接比较双精度数,并且应避免将它们用作关联容器的键。由于比较问题,您可能会发现在地图中找不到确实存在的元素。
  • @dribeas 非常好。我不得不替换一些在地图中使用双精度值作为键的代码,问题是查找任意失败。如果您坚持走这条路线,您可以通过提供自己的比较运算符来使其工作,该比较运算符使用 epsilon(或类似)进行比较
【解决方案3】:

如果您需要真正快速的关联容器,请尝试了解哈希。地图“足够快”,但在某些情况下并不出色。

尝试分析您需要存储的对象的结构是什么。如果字段是固定的,我建议不要使用嵌套地图。完全没有。地图通常用于“平均”数量的索引。对于数量少的简单列表更有效,因为插入/擦除操作的复杂性较低。对于大量索引,您确实需要考虑散列。

不要忘记记忆。 std::map 是高度动态的模板,因此由于动态分配,小对象存储了您大量的内存。这是你真正期待的吗?一旦我参与了 std::map 使用删除,这将内存需求降低了大约 2 倍。

如果您只需要在启动时填充地图并且只搜索元素(不需要更改结构),我建议您在插入所有元素后应用简单的 std::vector 排序。然后你可以只使用二进制搜索(因为你已经排序了向量)。为什么? std::vector 是更可预测的东西。最大的优点是内存区域连续。

【讨论】:

  • 是的,我确实需要继续添加数据。数据是并在运行时添加了很多。我现在一切正常,如果我每一步(游戏中的每帧)添加 1 位数据,它工作正常。但是一旦我一次做 2 个,我就会看到性能下降。我调查了这个哈希的东西,但找不到很多。仅供参考,物品商店的数量可能永远不会超过2000〜左右。所以我想它的规模相当小..
猜你喜欢
  • 2021-12-19
  • 1970-01-01
  • 2012-11-29
  • 1970-01-01
  • 2011-11-08
  • 2015-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多