【问题标题】:"Empty" array\vector members c++“空”数组\向量成员c ++
【发布时间】:2018-02-18 09:52:48
【问题描述】:

我必须通过从磁盘读取数据来填充 1000 个对象的数组。但是,并非所有对象都存在。

一旦我声明了一个数组,就会为 1000 个对象保留内存。 当我一一阅读它们时,我将内存设置为相应的值。但是,成员 #276 可能没有对象,并且它的内存将保持设置为声明数组时存在的任何内容。

如何保留数组的某些成员无效/不存在的信息?

我可以以某种方式将成员的所有字节设置为零,但这可能是一个有效的对象。

显而易见的解决方案是添加另一个字节数组,根据该索引处的对象是否存在,将其设置为 1 或 0,但这似乎不是很优雅。

这可以用矢量来代替吗?它可以以某种方式存储一个空值吗?

【问题讨论】:

  • 使用std::pair<Object, bool>,其中bool部分将指示对象是否被读取?
  • 使用指针代替对象实例?
  • 如果它是一个对象数组,如在结构或类中,那么让你的默认构造对象清楚地成为一个哨兵/空对象。如果空格的原因是保留索引值,请考虑将其作为对象的一部分或使用 map 或 unordered_map 等键/值容器,具体取决于您是否需要按顺序迭代它们。
  • 谷歌“稀疏矩阵”
  • 你不能只创建一个向量并只推回存在的元素吗?

标签: c++ arrays object vector sentinel


【解决方案1】:

从逻辑上讲,您需要跟踪存在的值以及哪些值中实际存储了数据。没有一种最好的方法可以做到这一点,您做出的选择将取决于您正在做什么。

在某些情况下 - 您的实现似乎不是其中之一 - 您可以保留一些特殊值,例如 nullptr-1 作为哨兵,并使用它来标记空槽。不过,您已经提到这里不存在此选项,因此我们将排除该选项。

另一个非常合理的选择是在每个槽中存储一个并行位向量或一些辅助数据,以标记该槽是否正在使用。如果您使用位向量,与您将用于元素本身的内存相比,此处所需的额外内存非常小。

上述两种方法的缺点是,如果您有一个真正巨大的数组(例如,数百万个元素),您将使用大量内存来存储未使用的插槽,既用于插槽本身,也用于任何额外的簿记。另一种选择是使用稀疏数据结构,如std::mapstd::unordered_map,从索引到元素的键,然后仅将元素加载到实际使用的稀疏结构中。这种方式查找单个元素的性能成本会稍慢一些,但内存增益可能很大。

【讨论】:

    【解决方案2】:

    可以用矢量代替吗?

    没有

    当然,如果您使用一些额外的空间来存储该信息(存在或不存在)或不存在对象的哨兵值。 std::vector 具有强大的根据其存储的元素数量调整自身大小的能力;所以如果它能满足你的要求,它就会失去那个能力。

    我会使用std::unordered_map,其中每个键都是对象的索引(例如#276),值是实际对象。如果对象不存在,请不要在映射中插入该键。

    或者std::map,如果您需要有效地迭代您的数据。 Choosing between std::map and std::unordered_map.


    要么真的很难找到一个哨兵值,它将你的数组中的一个单元格标记为空。例如,如果您已经在内存中的某处拥有数据(但我认为这不是您的情况),那么您可以使用指针数组,而不是存储整个对象的数组。那么很明显,NULL 指针将用于空单元格


    另一种选择是使用对数组,如下所示:std::pair<myClass, bool>,其中第二个操作数指示相应单元格是否为空。

    此外,您可以改用std::vector&lt;bool&gt;,它非常节省内存(如果您决定采用额外数据结构的方法),如Why does std::vector<bool> has no .data()? 中所述。然而,它将缺乏索引性能。

    【讨论】:

    • 我喜欢无序地图的方法。这是为了使代码尽可能简单。
    • 是的@Karlovsky120 我相信这个解决方案会产生干净的代码,如果你想不出你的数据的哨兵值! ;) 好问题顺便说一句,我赞成!
    • 我什至可能会使用常规地图,因为我可能不得不遍历它们......
    【解决方案3】:

    首先,请确保您确实担心有足够的内存来进行优化。 1000 个对象并不多,除非它们很大并且您希望它们稀疏。他们的指数重要吗?也就是说,如果您加载 2 个对象,是否可以将它们放入数组的元素 0,1 中,或者它们在数组中的位置是否重要,并且每个对象都有必须使用的特定数组索引?如果是这种情况,您最终可能会在数组中出现大洞,并且需要指示使用或不使用哪些元素(所以我不建议这样做。)相反,您可能会考虑初始化为的指针数组null,然后分配使用的元素,并在适当的索引处将相应的指针设置为它们。如果您可以压缩数组,则不妨使用向量。

    另一种选择是不将项目放入数组中,而是像树状图一样,它只保存您插入的元素,但仍然可以使用类似于数组索引的键找到。

    (注意:std::unordered_map 比 std::map 快,但哈希表过度分配内存(通常如果使用了 70% 的分配空间,则它们被认为是高负载的)并且问题的全部目的是减少内存使用。)

    【讨论】:

      猜你喜欢
      • 2011-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-13
      • 2019-05-19
      • 2020-08-18
      相关资源
      最近更新 更多