简体   繁体   English

std :: vector和多维数组的连续内存

[英]std::vector and contiguous memory of multidimensional arrays

I know that the standard does not force std::vector to allocate contiguous memory blocks, but all implementations obey this nevertheless. 我知道标准不会强制std::vector分配连续的内存块,但所有实现都遵循这一点。

Suppose I wish to create a vector of a multidimensional, static array. 假设我希望创建一个多维静态数组的向量。 Consider 2 dimensions for simplicity, and a vector of length N. That is I wish to create a vector with N elements of, say, int[5] . 为简单起见考虑2个维度,并考虑长度为N的向量。我希望创建一个具有N个元素的向量,比如int[5]

Can I be certain that all N*5 integers are now contiguous in memory? 我可以确定所有N * 5整数现在在内存中是连续的吗? So that I in principle could access all of the integers simply by knowing the address of the first element? 所以我原则上可以通过知道第一个元素的地址来访问所有整数? Is this implementation dependent? 这个实现依赖吗?

For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float* . 作为参考,我当前在连续内存块中创建2D数组的方法是首先创建一个长度为N的浮动*(动态)数组,在一个数组中分配所有N * 5个浮点数,然后将每个第5个元素的地址复制到float*的第一个数组。

The standard does require the memory of an std::vector to be contiguous. 该标准确实要求std::vector的内存是连续的。 On the other hand, if you write something like: 另一方面,如果你写的东西如下:

std::vector<std::vector<double> > v;

the global memory (all of the v[i][j] ) will not be contiguous. 全局内存(所有v[i][j] )将不是连续的。 The usual way of creating 2D arrays is to use a single 创建2D数组的常用方法是使用单个数组

std::vector<double> v;

and calculate the indexes, exactly as you suggest doing with float . 并准确计算索引,就像你建议使用float (You can also create a second std::vector<float*> with the addresses if you want. I've always just recalculated the indexes, however.) (如果需要,您还可以使用地址创建第二个std::vector<float*> 。但是,我总是只重新计算索引。)

Elements of a Vector are gauranteed to be contiguous as per C++ standard. 根据C ++标准,Vector的元素被保证为连续的。
Quotes from the standard are as follows: 标准引用如下:

From n2798 (draft of C++0x): 从n2798(C ++ 0x草案):

23.2.6 Class template vector [vector] 23.2.6类模板向量[向量]

1 A vector is a sequence container that supports random access iterators. 1 vector是一个支持随机访问迭代器的序列容器。 In addition, it supports (amortized) constant time insert and erase operations at the end; 此外,它支持(摊销)最后的恒定时间插入和擦除操作; insert and erase in the middle take linear time. 在中间插入和擦除需要线性时间。 Storage management is handled automatically, though hints can be given to improve efficiency. 存储管理是自动处理的,但可以提供提示以提高效率。 The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size(). 向量的元素是连续存储的,这意味着如果v是一个向量,其中T是某种类型而不是bool,那么它服从所有0 <= n <v的身份&v [n] ==&v [0] + n 。尺寸()​​。

C++03 standard (23.2.4.1): C ++ 03标准(23.2.4.1):

The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size(). 向量的元素是连续存储的,这意味着如果v是一个向量,其中T是某种类型而不是bool,那么它服从所有0 <= n <v的身份&v [n] ==&v [0] + n 。尺寸()​​。

Also, see here what Herb Sutter's views on the same. 此外,看到这里有什么香草萨特对了同样的观点。

As @Als already pointed out, yes, std::vector (now) guarantees contiguous allocation. 正如@Als已经指出的那样,是的, std::vector (now)保证了连续的分配。 I would not , however, simulate a 2D matrix with an array of pointers. 没有 ,但是,模拟2D矩阵具有指针的阵列。 Instead, I'd recommend one of two approaches. 相反,我建议采用两种方法之一。 The simpler by (by far) is to just use operator() for subscripting, and do a multiplication to convert the 2D input to a linear address in your vector: (到目前为止)更简单的方法是使用operator()进行下标,并进行乘法以将2D输入转换为向量中的线性地址:

template <class T>
class matrix2D { 
     std::vector<T> data;
     int columns;
public:
     T &operator()(int x, int y) {
         return data[y * columns + x];
     }

     matrix2D(int x, int y) : data(x*y), columns(x) {}
};

If, for whatever reason, you want to use matrix[a][b] style addressing, you can use a proxy class to handle the conversion. 无论出于何种原因,如果您想使用matrix[a][b]样式寻址,您可以使用代理类来处理转换。 Though it was for a 3D matrix instead of 2D, I posted a demonstration of this technique in previous answer . 虽然它是用于3D矩阵而不是2D,但我在之前的回答中发布了这种技术的演示。

For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*. 作为参考,我当前在连续内存块中创建2D数组的方法是首先创建一个长度为N的浮动*(动态)数组,在一个数组中分配所有N * 5个浮点数,然后将每个第5个元素的地址复制到float *的第一个数组。

That's not a 2D array, that's an array of pointers. 那不是2D数组,这是一个指针数组。 If you want a real 2D array, this is how it's done: 如果你想要一个真正的2D数组,这就是它的完成方式:

float (*p)[5] = new float[N][5];

p [0] [0] = 42;   // access first element
p[N-1][4] = 42;   // access last element

delete[] p;

Note there is only a single allocation. 请注意,只有一个分配。 May I suggest reading more about using arrays in C++ ? 我可以建议阅读有关在C ++中使用数组的更多信息吗?

Under the hood, a vector may look approximately like (p-code): 在引擎盖下,矢量可能看起来大致相似(p代码):

class vector<T> {
    T      *data;
    size_t  s;
};

Now if you make a vector<vector<T> > , there will be a layout like this 现在,如果你创建一个vector<vector<T> > ,就会出现这样的布局

vector<vector<T>> --> data {
    vector<T>,
    vector<T>,
    vector<T>
};

or in "inlined" form 或以“内联”形式

vector<vector<T>> --> data {
    {data0, s0},
    {data1, s1},
    {data2, s2}
};

Yes, the vector-vector therefore uses contiguous memory, but no, not as you'd like it. 是的,矢量矢量因此使用连续的内存,但不是,不是你想要的。 It most probably stores an array of pointers (and some other variables) to external places. 它很可能将一个指针数组(和一些其他变量)存储到外部位置。

The standard only requires that the data of a vector is contiguous, but not the vector as a whole. 该标准仅要求矢量的数据是连续的,而不是整个矢量。

A simple class to create, as you call it, a 2D array , would be something like: 一个简单的类,就像你所说的那样,创建一个2D数组 ,就像这样:

template <class T> 2DArray {
private:
    T *m_data;
    int m_stride;
public:
    2DArray(int dimY, int dimX) : m_stride(dimX) : m_data(new[] T[dimX * dimY]) {}
    ~2DArray() { delete[] m_data; }
    T* operator[](int row) { return m_data + m_stride * row; }
}

It's possible to use this like: 有可能使用它:

2DArray<int> myArray(30,20);

for (int i = 0; i < 30; i++)
    for (int j = 0; j < 20; j++)
        myArray[i][j] = i + j;

Or even pass &myArray[0][0] as address to low-level functions that take some sort of "flat buffers". 或者甚至将&myArray[0][0]作为地址传递给采用某种“平缓冲”的低级函数。

But as you see, it turns naive expectations around in that it's myarray[y][x] . 但正如你所看到的,它变成了天真的期望,因为它是myarray[y][x]

Generically, if you interface with code that requires some sort of classical C-style flat array, then why not just use that ? 通常,如果您与需要某种经典C风格平面阵列的代码接口,那么为什么不使用它呢?

Edit: As said, the above is simple . 编辑:如上所述,上面很简单 No bounds check attempts whatsoever. 没有任何限制检查尝试。 Just like, "an array". 就像“阵列”一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM