【问题标题】:Can you predict where in memory a vector might move when growing?你能预测一个向量在增长时可能在内存中移动的位置吗?
【发布时间】:2015-06-09 16:59:55
【问题描述】:

我正在学习 C++ 并且有一个概念性问题。假设我有一个向量。我知道我的向量存储在连续的内存中,但是假设我的向量不断增长并且空间不足以保持内存连续。如何预测向量在内存中的位置?我排除了使用函数来告诉向量它应该在内存中的位置的选项。

【问题讨论】:

  • 需要知道什么用例?
  • 如果可以,对您有什么好处?在增长之前你不能使用新地址,之后你不能使用旧地址,在这两种情况下你都不应该使用实际地址。
  • @Barry - 我认为他正在尝试学习行为并发现一些内部运作。那就是如果我正确解析:“我正在学习 C++ 并且有一个概念性问题”.
  • @jww 你是对的。我没有特定的用例。我一直在看关于 C++ 中向量的视频,想到了这个问题,但找不到答案(直到现在)。

标签: c++ pointers memory vector


【解决方案1】:

如果它“没有足够的空间来保持内存连续”,那么它就不会增长。尝试添加超过当前分配大小的项目(通常)会导致其抛出异常(尽管从技术上讲,由分配器对象决定要做什么——它负责内存分配,并在不可能时做出响应。

但是请注意,这可能是由于地址空间不足(尤其是在 32 位机器上)而不是实际内存不足所致。一个典型的虚拟内存管理器可以重新分配物理页面(例如,4 KB 或 8 KB 块)并在必要时将数据写入页面文件以释放物理内存(如果需要)——但是当/如果没有足够的连续地址空间时,没有太多这是可以做到的。

【讨论】:

  • std::vector<>(cplusplus.com/reference/vector/vector) 是一个能够增长到所需大小的动态容器,前提是可以从为其构造函数提供的任何分配器分配足够的内存。
【解决方案2】:

答案很大程度上取决于您的分配策略,但总的来说,答案是否定的。大多数分配器不会为您提供下一次分配将在何处发生的信息。如果您正在编写自定义分配器,那么您可能会使此信息可访问,但这样做不一定是一个好主意,除非您的用例特别需要此知识。

realloc 函数是唯一会尝试在适当位置增加内存的 C 函数,它不保证一定会这样做。

newmalloc 均未提供有关“下一次”分配将在何处进行的任何信息。如果您知道特定编译器的确切实现细节,您可能会猜到,但这在实际程序中依赖是非常不明智的。特别是用于std::vectorstd::allocator,它也没有提供有关未来分配将在何处进行的详细信息。

【讨论】:

    【解决方案3】:

    即使您可以在特定情况下预测它,它也会非常脆弱 - 您只需调用一个函数来更改以再次调用 newmalloc [除非您使用的是非常具体的分配方法——不同于“通常”的方法]到“中断”下一次分配的地方。

    如果你知道你需要一个特定的大小,你可以使用std::vector::resize()来设置向量的大小[或者std::vector<int> vec(10000);来创建一个预先设置为10000的大小,例如]——当然不能保证工作,但它保证你永远不需要“足够的空间来容纳当前内容的 3 倍”,当你使用 std::vector 增长它时会发生这种情况 push_back [如果你真的很不幸,这意味着你的向量将使用2*n-1 元素,留下n-1 未使用,因为您的大小是n-1,并且您添加了一个元素,这使大小加倍,所以现在2*n,您实际上只需要一个元素...

    【讨论】:

      【解决方案4】:

      出于充分的理由,STL 容器的内部运作保持私密。您不应该通过适当的迭代器以外的任何机制访问任何容器元素;并且不可能在尚不存在的元素上获得其中之一。

      但是,您可以提供一个分配器并使用它来确定性地放置未来的分配。

      【讨论】:

        【解决方案5】:

        你能预测一个向量在增长时可能在内存中移动的位置吗?

        正如 EJP、Jerry 和 Mats 等其他人所说,在“生长”矢量生长之前,您无法确定它的位置。有一些极端情况,例如分配器提供的内存块大于所需的内存块,因此向量在增长后实际上不会移动。但它不是你应该依赖的东西。

        一般来说,栈向下增长,堆向上增长。这是来自旧记忆时代的神器。您的代码段夹在它们之间,它确保您的程序会覆盖自己的代码段并最终导致非法指令。因此,您可能能够猜测新向量在内存中将比旧向量更高,因为该向量可能正在使用堆内存。但它并不是真正有用的信息。

        如果您正在设计一种在增长后定位元素的策略,那么请使用索引而不是迭代器。迭代器在插入和删除(包括增长)后失效。

        例如,假设您正在解析向量并且正在查找-----BEGIN CERTIFICATE----- 之后的数据。一旦您知道数据的偏移量(向量中的字节 27),您就可以始终使用v.begin() + 26 在恒定时间内重新定位它。如果您只有部分证书,然后添加数据的尾部和-----END CERTIFICATE-----(并且向量增长),那么数据仍然位于v.begin() + 26

        【讨论】:

          【解决方案6】:

          不,实际上,如果由于调整大小而必须移动,您无法预测它会去哪里。但是,它并不是那么随机,您可以将其用作随机数生成器 (;

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-01-24
            • 2015-09-03
            • 2012-07-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-05
            相关资源
            最近更新 更多