为什么矢量保证不是连续的? (或者是吗?)

时间:2013-04-05 00:42:52

标签: c++ stdvector

我知道std::vector元素在内存中保证是连续的。

那么为什么你不能指望包含其他向量的向量使整个集合连续?

该向量应该保证其封闭项的连续内存布局,如果这些外壳也是向量,那么我希望最顶层向量的全部内容在连续的内存中。

但是在这个问题上似乎存在一些关于这是否属实的争论。一个人可以安全地依赖它吗?有些人似乎go out of their way来实现这一目标,而我认为这是有保障的。

6 个答案:

答案 0 :(得分:5)

向量向量中的每个向量都是一个单独的对象,因此负责它的存储。所以,不,它绝不是保证是连续的,事实上我真的看不到可能发生的情况是存储在外部向量中的数据和它的内部向量是一个连续的内存块。

答案 1 :(得分:3)

我认为回答这个问题的最正确的正式方式(与描述现有的实现相反)是基于§23.3.6.1/ 1:

  

[...]向量的元素是连续存储的,这意味着如果vvector<T, Allocator>,其中T是某种类型而不是bool,那么它就是服从身份

&v[n] == &v[0] + n
     

适用于所有0 <= n < v.size()

请注意,这涉及向量的各个元素的地址&v[i],并且特别暗示向量的每个元素具有常量大小sizeof(T)(因为这是指针算法的工作原理)。

这意味着矢量元素不可能在运行时改变大小。如果vector<vector<T>>被实现为一个连续的内存块,那么外部向量的成员(它们本身就是向量)将被允许改变大小。

因此,必须有一个额外的间接级别,即,各个向量必须包含某种指向存储在不同位置的可变大小数据结构的指针。

答案 2 :(得分:2)

向量是一个包含指向实际数组的指针的对象。

向量向量将是一个带有指向对象数组的指针的对象,每个对象都指向堆上其他位置的自己的数组。所以不,他们永远不会以你要求的方式连续。

答案 3 :(得分:0)

让我们看一下vector的(逻辑)内存布局:

[size:4/8 bytes]
[capacity:4/8 bytes]
[other datamembers:n bytes]
*[elements:size*sizeof(element) bytes] << one contiguous memory (pointer to heap)

使用矢量矢量,它看起来像这样:

[size:4/8 bytes]
[capacity:4/8 bytes]
[other datamembers:n bytes]
* [
    [Vector:0]
        [size:4/8 bytes]
        [capacity:4/8 bytes]
        [other datamembers:n bytes]
        *[elements:size*sizeof(element) bytes] << pointer to contiguous memory for elements
    [Vector:1]
        [size:4/8 bytes]
        [capacity:4/8 bytes]
        [other datamembers:n bytes]
        *[elements:size*sizeof(element) bytes]
    [Vector:2]
        [size:4/8 bytes]
        [capacity:4/8 bytes]
        [other datamembers:n bytes]
        *[elements:size*sizeof(element) bytes]
    ...
    ...
] << contiguous memory of vectors

这意味着向量具有指向存储向量的连续内存的指针,每个向量存储指向另一个堆的元素,其中存储元素的连续内存。

但是如果你设法创建一个由向量​​使用的分配器,这样它就会分配连续的内存块,你仍然会面临一个问题,即如果其中一个嵌套向量被删除,那么内存就不会更长的连​​续。更不用说嵌套向量具有不同大小的情况。

根据您的使用情况,您可以使用客户连续的块内存分配器作为向量向量,或者只使用手动分配和释放一个连续内存块的旧方法。

答案 4 :(得分:0)

问题是矢量模板不包含它“内联”或直接处理的数据。另一种说法是向量类对它所拥有的数据数组进行包装:向量类包含一个指向包含元素数组的内存区域的指针。它在结构上等同于:

template <typename T>
struct vector_eq {
    T *ptr;
};

而不是

template <typename T>
struct vector_neq {
    T arr[SIZE];
};

这需要在编译时知道SIZE(即constexpr),以便将arr元素包含在结构中。

我想,应该可以专门化vector<vector<T>>来包含指向单个内存块的指针,并使其方法返回vector<T>共享该内存块切片的临时实例,尽管它背后的逻辑可能有点毛茸茸。

答案 5 :(得分:0)

简单地说 - std :: vector保证元素是连续存储的。但是这只包括元素的成员数据,在矢量的情况下,它的大小,容量和类似的东西,加上指向实际矢量数据的指针。

因此,向量向量将为您提供一个连续的向量向量,但这些向量将动态分配在任意内存地址上。

由于在编译时需要知道对象大小,因此不能使用不同大小的对象,唯一的方法是使用动态内存分配。如果你有一个固定大小的自定义向量,它在内部不使用动态内存,那么std::vector<customVector>会连续存储customVectors,但你仍然会有其他辅助成员来“中断”customVector的实际连续性元素数据。