我知道标准不会强制std::vector
分配连续的内存块,但所有实现都遵循这一点。
假设我希望创建一个多维静态数组的向量。为简单起见考虑2个维度,并考虑长度为N的向量。我希望创建一个包含N个元素的向量,比如int[5]
。
我可以确定所有N * 5整数现在在内存中是连续的吗?所以我原则上可以通过知道第一个元素的地址来访问所有整数?此实现是否依赖?
作为参考我当前在连续内存块中创建2D数组的方法是首先创建一个长度为N的浮动*(动态)数组,在一个数组中分配所有N * 5个浮点数然后复制每个数据的地址第5个元素到float*
的第一个数组。
答案 0 :(得分:13)
标准确实需要std::vector
的内存
连续的。另一方面,如果你写了类似的东西:
std::vector<std::vector<double> > v;
全局内存(所有v[i][j]
)都不会连续。该
创建2D数组的常用方法是使用单个
std::vector<double> v;
并完全按照您对float
的建议计算索引。
(您还可以使用地址创建第二个std::vector<float*>
如果你想。不过,我总是只是重新计算索引。)
答案 1 :(得分:5)
根据C ++标准,Vector的元素是连续的 标准引用如下:
从n2798(C ++ 0x草案):
23.2.6班级模板载体[vector]
1向量是一个支持随机访问迭代器的序列容器。此外,它支持(摊销)最后的恒定时间插入和擦除操作;在中间插入和擦除需要线性时间。存储管理是自动处理的,但可以提供提示以提高效率。向量的元素是连续存储的,这意味着如果v是一个向量,其中T是除了bool之外的某种类型,那么它服从所有0&lt的同一性&amp; v [n] ==&amp; v [0] + n ; = n&lt; v.size()。
C ++ 03标准(23.2.4.1):
向量的元素是连续存储的,这意味着如果v是一个向量,其中T是某种类型而不是bool,那么它就服从身份&amp; v [n] ==&amp; v [0] + n表示所有0&lt; = n&lt; v.size()。
另外,请参阅here Herb Sutter对此的看法。
答案 2 :(得分:3)
正如@Als已经指出的那样,是的,std::vector
(现在)保证了连续的分配。然而,我会不模拟带有指针数组的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,但我在previous answer中发布了这种技术的演示。
答案 3 :(得分:3)
作为参考我当前在连续内存块中创建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;
请注意,只有一个分配。我可以建议您阅读更多关于using arrays in C++的内容吗?
答案 4 :(得分:1)
在引擎盖下,矢量看起来大致相似(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}
};
是的,矢量矢量因此使用连续的内存,但不是,不是你想要的。它很可能将一个指针数组(和一些其他变量)存储到外部位置。
标准只要求矢量的数据是连续的,而不是整个矢量。
答案 5 :(得分:1)
一个简单的类,就像你所说的那样,创建一个 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风格平面阵列的代码接口,那么为什么不直接使用呢?
编辑:如上所述,上面是简单。没有任何限制检查尝试。就像“阵列”一样。