2017-02-24 63 views
1

考虑下面的代码,其中分配大小5×3的2D std::vector<std::vector<int> >并打印各元素的存储器地址:2d std :: vector连续内存?

#include <iostream> 
#include <vector> 

int main() { 
    int n = 5, m = 3; 
    std::vector<std::vector<int> >vec (n, std::vector<int>(m)); 

    for (int i = 0; i < n; ++i) { 
    for (int j = 0; j < m; ++j) { 
     std::cout << &(vec[i][j]) << " "; 
    } 
    std::cout << "\n"; 
    } 
} 

输出:

0x71ecc0 0x71ecc4 0x71ecc8 
0x71ece0 0x71ece4 0x71ece8 
0x71ed00 0x71ed04 0x71ed08 
0x71ed20 0x71ed24 0x71ed28 
0x71ed40 0x71ed44 0x71ed48 

当然,对于一个固定的行,每列在内存中都是连续的,但行不是。特别是,每一行在前一行的开始之后是32个字节,但由于每行只有12个字节,这留下了20个字节的间隔。例如,因为我认为vectors分配连续的内存,我会期望第二行的第一个地址是0x71eccc。为什么不是这样,vector如何决定给予多少差距?

+1

你为什么期待?向量开销大小不为0 ... –

+1

如果您希望数据连续,请分配一个大小为“n * m”的单个向量,然后自己进行偏移量计算。 –

+0

或者使用'std :: array ,n>'为0开销。如果您需要动态容器,请执行@NeilButterworth建议的操作。 – user2176127

回答

2

向量的开销大小不为0.在向量的最后一个元素和下一个向量的第一个元素之间有24个字节。试试这个:

cout << sizeof(std::vector<int>) << endl; 

你会发现输出为24(很有可能为你实现的std ::向量和编译器等的)。 Live example which happens to match

你可以想象矢量布局是这样的:

enter image description here

如果你希望你的元素实际上是连续的,那么你需要做的:

  1. 使用std::array<std::array<int>>为无开销( C++ 11 only)。请注意,这不能调整大小。
  2. 使用std::vector<int>和公式row * numRows + col访问row, col的元素。
+0

请记住'sizeof(std :: vector )'是大量实现定义的。 – user2176127

+0

〜4字节的std :: vector通常用于分配器 – user2176127

+0

@Fantastic Mr Fox在'c8'和'e0'之间只有20个字节。 24在哪里适合这里? – bcf

1

同意Fox先生的结果和解决方案。不同意用来到达那里的逻辑。

为了调整大小的,一个std::vector包含连续的存储器的动态分配的块,因此,外vector有一个指针指向包含N个vector s表示是连续的存储块。但是,这些内部中的每一个都包含一个指向其自己的存储块的指针。所有N个存储块连续存在的可能性(没有一些非常流行的自定义分配器伏都教)是惊人的小。 N vector的开销是连续的。这些数据几乎肯定不是,但可能是。

大部分。 std::vector中的std::array将是连续的,但是没有任何东西阻止std::array的实现者输入其他状态信息,以防止std::array中的数组连续不断。一个以这种方式编写std::array的实现者是一个奇怪的顶部空间的使用者,或者解决一个非常有趣的问题。

+0

你的第二点是非常哲学的。虽然这个标准可能确实意味着'sizeof(std :: array )== sizeof(T)* N'成立,但没有定义它,但实际上大多数主要编译器都是这样。 – user2176127

+0

@ user2176127同意。我不希望任何人不经过任何努力去找到或找到它,就会遇到这个问题。 – user4581301