【问题标题】:drawback to vector.reserve(10000000) because i want to keep original memory locations?vector.reserve(10000000) 的缺点是因为我想保留原始内存位置?
【发布时间】:2020-10-14 21:54:03
【问题描述】:

我在运行时使用 vector.push_back() 创建对象,并且我想存储播放器对象,以便我可以随时使用它。所以我将刚刚创建的播放器的指针存储到一个全局指针变量中,但是当我推回下一个对象时,播放器的内存地址会发生变化,我认为是因为向量必须调整大小,因此会更改其所有元素的位置。

for (int y = 0; y < 5; y++)
{
    for (int x = 0; x < 10; x++)
    {
        switch (map[x + 10 * y])
        {
        case '1':
            gameObjects.push_back(player);
            playerPointer = &gameObjects.back();
            break;
        case '2':
            gameObjects.push_back(block);
            gameObjects.back().transform.pos = vec((float)x * 100, (float)y * 150, 0);
            break;
        }
    }
}

但是当我使用时

gameObjects.reserve(10000);

位置不会改变,因为它是保留的,在这种情况下直到大小变为 10000 才需要调整大小。

那么问题是什么?你可以只保留(1000000000)而没有任何后果吗?我的 RAM 使用量并没有飙升。

提前致谢

【问题讨论】:

  • 当然,您可以保留任意多的空间。如果它未能分配内存,它将引发异常。但是,这似乎是解决您的问题的一种非常糟糕的方法。您可以存储对向量的引用以及索引,而不是存储指向向量中对象的原始指针。或者如果你很懒,你可以换成std::deque。它永远不会重新分配它的元素。
  • 指数可以稳定。有时std::list 是一种替代方案(它具有更稳定的迭代器),但请考虑缺点
  • "当我推回下一个对象时,播放器的内存地址会改变"我认为你有一个 XY 问题。真正的问题是,如果这个地址发生变化,为什么重要?是因为您试图将指向该对象的直接指针存储在其他地方吗?那么也许你应该做其他事情——例如,只存储一个数字索引,用于索引向量;或使用某种智能指针类型;或存储索引与指向向量的指针的组合。或者反过来:将智能指针存储在向量中,并将一个指向硬编码的player
  • @KarlKnechtel 我同意一些扩展,但显然不是 X playerPointer = &amp;gameObjects.back(); 吗?虽然,是的,这个例子可能更清楚,因为实际问题不在这段代码中,而是在其他一些使用 playerPointer 且假设错误的代码中
  • 我有时很难阅读和理解问题中的所有信息 :)

标签: c++ vector


【解决方案1】:

reserve( a lot ) 的缺点是您可以保留太多,这会浪费内存,或者太少,仍然会发生重新分配。

当迭代器失效时,指向元素的指针也会失效。当迭代器失效时,我建议您参考这个问题:Iterator invalidation rules

面对现实:std::vectors 迭代器相当不稳定(因此也指向元素的指针)。您有多种选择:

  • 预先预留足够的空间可能是一种解决方案,尽管它并不安全。一旦推送的数量超过了预留的数量,迭代器就会关闭。
  • 如果您可以为最大数量的元素保留足够的空间,您也可以使用std::array
  • 使用索引。假设您不对向量重新排序并且从不移除元素,则索引是稳定的。
  • 使用std::list。列表的迭代器比向量的迭代器稳定得多。特别是,插入列表不会使迭代器无效。不过,请考虑 std::liststd::vector 相比的缺点。
  • 将元素存储在别处。除了将player 存储在向量中,您还可以将指向它的(智能)指针存储在向量中。重新排序或重新分配向量不会影响指向实际对象的指针。

【讨论】:

    【解决方案2】:

    在我发布这篇文章后很快我意识到使用指针作为 ID 是愚蠢的(尤其是使用向量)所以我只是给游戏对象一个 const char* 名称并创建了一个函数循环遍历我的游戏对象直到它找到一个名称你寻找并归还它。我将 GameObject* 设置为函数返回的游戏对象*,然后我可以使用 player->doStuff

    【讨论】:

    • 保留句柄以避免为每次访问搜索容器并不愚蠢!另外我想提一下,您在此答案中引用的上下文正是您的问题中缺少的内容。没有人可以,但您可以仅根据您的问题得出这个答案。只是说...
    • 是的,我知道,我的错,我认为使用指针是要走的路,直到我意识到完全不同的方法
    猜你喜欢
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-19
    相关资源
    最近更新 更多