C++ Vectors 如何不使用默认构造函数在内存 space 中覆盖?

How do C++ Vectors not overwrite within memory space with default constructor?

这与其说是一个问题,不如说是一个理论问题。

据我了解,std::vector 将在添加、删除或构建时动态 resize/reallocate 内存。

我有几个关于矢量如何在最低级别工作的问题,使用下面的代码示例

  1. 是什么阻止了以下示例覆盖 string1 的内存 space?

  2. 向量是否像数组一样连续?

  3. 如果有一个向量需要的总可用内存,但它不是连续的,它会整理内存碎片吗space?

#include <vector>

using namespace std;

int main(){
    string string1 = "Some really large string";  

    /* A bunch of other random declarations take place 
    ...
    */

    vector<int> vector1;

    for(int i = 0; i < 10; i++)
    {
       vector1.push_back(i);
    }
}

这些答案怎么样?

  1. OS 会(或处理您的内存分配的任何人)。通常向量和字符串的默认分配器调用 OS 在堆上分配内存。 (非常小的字符串可能会通过“小字符串优化,<~16 字节字符串”进入堆栈)。OS 确保它们不会发生冲突。

  2. 是的,标准保证向量的连续内存。

  3. 不,它将请求它需要的大小块并且 OS(或任何分配器)将提供一个或失败。碎片整理是一项 OS 任务。

编辑:@parktomatomi 所说的是正确的。 std::vector<T> 为开始的 8 个元素分配足够的内存,然后对于第 9 个元素,他们将重新请求 16 个元素,复制所有内容并在 32 个元素处再次释放第 8 个元素 block.Same 等。边界是实现相关的,但它是这样的。您可以使用 std::vector.reserve() 来避免重新分配和复制过程。只有当你有完美的信息时通常才值得这样做,否则将它留给加倍算法通常就可以了。

std::array<T, N> 是固定大小的, 堆栈分配 就像原始类型(int、double 等)一样。所以它的大小受到堆栈的限制。

Stack 也不会破坏(很明显),因为它 "moves the stack pointer down into new space" 每个变量声明。

现代 desktop/server 机器上的典型堆栈大小在 linux/OSX 上为 8MB,在 Windows 上为 1MB。这些是可以调整的。堆大小(向量所在的位置)仅受机器中物理内存的限制(如果您不介意交换到磁盘,实际上是虚拟内存)。所以通常是几个 GB。

这篇关于这个主题的文章不错。 https://www.tutorialspoint.com/cplusplus/cpp_dynamic_memory.htm

但请注意,它谈论了很多关于 newdelete 的内容。 99% 的时间你不应该使用那些。它们将在 std::vector 构造函数和析构函数(以及更多地方)的实现中发生 "automatically"。

std::vector<T> 在运行时分配内存。 OS 给了它一大块内存,它位于地址 space 的其他地方,而 std::vector 只保存指向它的指针(地址),所以 sizeof(std::vector<T>) 总是一些固定大小,不会溢出堆栈中的下一个东西。

当你推回足够多的元素时,std::vector 的实现通常会分配一个全新的内存缓冲区,并复制所有旧内存。这样,即使缓冲区中的空间不足,内存也会保持连续。这会对逐个元素增长向量产生小的惩罚,因此如果您知道它的大小,my_vector.reserve(N) 将确保它有足够的 space 用于 N 个元素而无需重新分配。

std::array<T, N> 的工作方式更像您的想法,就像一个 C 数组,其中所有内存都是对象的一部分。因此,std::array 无法调整大小。