繁体   English   中英

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

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

我知道标准不会强制std::vector分配连续的内存块,但所有实现都遵循这一点。

假设我希望创建一个多维静态数组的向量。 为简单起见考虑2个维度,并考虑长度为N的向量。我希望创建一个具有N个元素的向量,比如int[5]

我可以确定所有N * 5整数现在在内存中是连续的吗? 所以我原则上可以通过知道第一个元素的地址来访问所有整数? 这个实现依赖吗?

作为参考,我当前在连续内存块中创建2D数组的方法是首先创建一个长度为N的浮动*(动态)数组,在一个数组中分配所有N * 5个浮点数,然后将每个第5个元素的地址复制到float*的第一个数组。

该标准确实要求std::vector的内存是连续的。 另一方面,如果你写的东西如下:

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

全局内存(所有v[i][j] )将不是连续的。 创建2D数组的常用方法是使用单个数组

std::vector<double> v;

并准确计算索引,就像你建议使用float (如果需要,您还可以使用地址创建第二个std::vector<float*> 。但是,我总是只重新计算索引。)

根据C ++标准,Vector的元素被保证为连续的。
标准引用如下:

从n2798(C ++ 0x草案):

23.2.6类模板向量[向量]

1 vector是一个支持随机访问迭代器的序列容器。 此外,它支持(摊销)最后的恒定时间插入和擦除操作; 在中间插入和擦除需要线性时间。 存储管理是自动处理的,但可以提供提示以提高效率。 向量的元素是连续存储的,这意味着如果v是一个向量,其中T是某种类型而不是bool,那么它服从所有0 <= n <v的身份&v [n] ==&v [0] + n 。尺寸()​​。

C ++ 03标准(23.2.4.1):

向量的元素是连续存储的,这意味着如果v是一个向量,其中T是某种类型而不是bool,那么它服从所有0 <= n <v的身份&v [n] ==&v [0] + n 。尺寸()​​。

此外,看到这里有什么香草萨特对了同样的观点。

正如@Als已经指出的那样,是的, std::vector (now)保证了连续的分配。 没有 ,但是,模拟2D矩阵具有指针的阵列。 相反,我建议采用两种方法之一。 (到目前为止)更简单的方法是使用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) {}
};

无论出于何种原因,如果您想使用matrix[a][b]样式寻址,您可以使用代理类来处理转换。 虽然它是用于3D矩阵而不是2D,但我在之前的回答中发布了这种技术的演示。

作为参考,我当前在连续内存块中创建2D数组的方法是首先创建一个长度为N的浮动*(动态)数组,在一个数组中分配所有N * 5个浮点数,然后将每个第5个元素的地址复制到float *的第一个数组。

那不是2D数组,这是一个指针数组。 如果你想要一个真正的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;

请注意,只有一个分配。 我可以建议阅读有关在C ++中使用数组的更多信息吗?

在引擎盖下,矢量可能看起来大致相似(p代码):

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

现在,如果你创建一个vector<vector<T> > ,就会出现这样的布局

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

或以“内联”形式

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

是的,矢量矢量因此使用连续的内存,但不是,不是你想要的。 它很可能将一个指针数组(和一些其他变量)存储到外部位置。

该标准仅要求矢量的数据是连续的,而不是整个矢量。

一个简单的类,就像你所说的那样,创建一个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; }
}

有可能使用它:

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

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

或者甚至将&myArray[0][0]作为地址传递给采用某种“平缓冲”的低级函数。

但正如你所看到的,它变成了天真的期望,因为它是myarray[y][x]

通常,如果您与需要某种经典C风格平面阵列的代码接口,那么为什么不使用它呢?

编辑:如上所述,上面很简单 没有任何限制检查尝试。 就像“阵列”一样。

暂无
暂无

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

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