我想创建一个在C++中返回连续2D数组的函数.
使用以下命令创建阵列不是问题:
int (*v)[cols] = new (int[rows][cols]);
Run Code Online (Sandbox Code Playgroud)
但是,我不知道如何将此数组作为函数的常规类型返回.功能是:
NOT_SURE_WHAT_TYPE create_array(int rows, int cols)
{
int (*v)[cols] = new (int[rows][cols]);
return v;
}
Run Code Online (Sandbox Code Playgroud)
我尝试了双*[]和双**,两者都不起作用.我不想使用double*,因为我想从外部访问这个数组作为2D数组.
相关问题:如何使用new在C++中声明二维数组?
Pau*_*zie 25
如果要创建一个数据连续的数组,并且您不想要一维数组(即您想使用[][]语法),那么以下内容应该可行.它创建一个指针数组,每个指针指向一个内存池的位置.
#include <iostream>
#include <exception>
template <typename T>
T** create2DArray(unsigned nrows, unsigned ncols, const T& val = T())
{
if (nrows == 0)
throw std::invalid_argument("number of rows is 0");
if (ncols == 0)
throw std::invalid_argument("number of columns is 0");
T** ptr = nullptr;
T* pool = nullptr;
try
{
ptr = new T*[nrows]; // allocate pointers (can throw here)
pool = new T[nrows*ncols]{val}; // allocate pool (can throw here)
// now point the row pointers to the appropriate positions in
// the memory pool
for (unsigned i = 0; i < nrows; ++i, pool += ncols )
ptr[i] = pool;
// Done.
return ptr;
}
catch (std::bad_alloc& ex)
{
delete [] ptr; // either this is nullptr or it was allocated
throw ex; // memory allocation error
}
}
template <typename T>
void delete2DArray(T** arr)
{
delete [] arr[0]; // remove the pool
delete [] arr; // remove the pointers
}
int main()
{
try
{
double **dPtr = create2DArray<double>(10,10);
dPtr[0][0] = 10; // for example
delete2DArray(dPtr); // free the memory
}
catch(std::bad_alloc& ex)
{
std::cout << "Could not allocate array";
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,只完成了2次分配.另请注意如何释放内存.您可以通过将此设置为真正的类而不是将分配/释放作为2个单独的函数来改进设计.
编辑:该类不像RAII那样,就像评论所说的那样.我把它作为读者的练习.上面代码中缺少的一件事是在创建这样的数组时检查nRows和nCols是否> 0.
编辑2:添加了一个new[]以确保在for尝试分配内存时抛出异常,以确保正确回滚内存分配.
编辑:对于类似于上面的代码的3维数组示例,请参阅此答案.包括在分配失败时回滚分配的代码.
除非在编译时知道这两个维度的大小,否则您没有太多选择:分配单个s rows*cols数组int,并使用整数乘法和加法滚动自己的2D索引.在类中包装它可以产生一个漂亮的语法,用于访问带方括号运算符的数组元素.由于您的数组是2D,因此您需要使用代理(AKA"代理")对象进行第一级数据访问.
这是一个std::vector<T>用于在动态内存中维护连续内存区域的小示例代码:
template<class T>
class Array2D {
vector<T> data;
size_t cols;
public:
// This is the surrogate object for the second-level indexing
template <class U>
class Array2DIndexer {
size_t offset;
vector<U> &data;
public:
Array2DIndexer(size_t o, vector<U> &dt) : offset(o), data(dt) {}
// Second-level indexing is done in this function
T& operator[](size_t index) {
return data[offset+index];
}
};
Array2D(size_t r, size_t c) : data (r*c), cols(c) {}
// First-level indexing is done in this function.
Array2DIndexer<T> operator[](size_t index) {
return Array2DIndexer<T>(index*cols, data);
}
};
Run Code Online (Sandbox Code Playgroud)
您现在可以使用Array2D<int>它就像是一个内置的C++数组:
Array2D<int> a2d(10, 20);
for (int r = 0 ; r != 10 ; r++) {
for (int c = 0 ; c != 20 ; c++) {
a2d[r][c] = r+2*c+1;
}
}
Run Code Online (Sandbox Code Playgroud)
处理原始内存资源往往是icky.最好的镜头是一个简单的包装:
struct array2D : private std::vector<int>
{
typedef std::vector<int> base_type;
array2D() : base_type(), height_(0), width_(0) {}
array2D(std::size_t h, std::size_t w) : base_type(h*w), height_(h), width_(w);
int operator()(std::size_t i, std::size_t j) const
{
return base_type::operator[](i+j*height_);
}
int& operator()(std::size_t i, std::size_t j)
{
return base_type::operator[](i+j*height_);
}
std::size_t rows() const { return height_; }
std::size_t cols() const { return width_; }
private:
std::size_t height_, width_;
}
Run Code Online (Sandbox Code Playgroud)
私有继承让你从vector中获取所有好东西,只需添加你的2D构造函数.资源管理是免费的,因为矢量ctor/dtor将发挥他们的魔力.显然,i + h*j可以改为你想要的存储顺序.
vector <vector <int >>是2D,但在内存中不是连续的.
你的功能变成:
array2D create_array(int rows, int cols)
{
return array2D(cols,rows);
}
Run Code Online (Sandbox Code Playgroud)
编辑:
您还可以使用usign子句检索其他向量接口部分(如begin/end或size),以使私有继承的成员函数再次公开.
由于你使用的是C++而不是C,我建议使用一个向量而不是使用new/delete.
您可以像这样定义一个连续的内存块:
std::vector<int> my_matrix(rows*cols);
Run Code Online (Sandbox Code Playgroud)
现在,您使用公式i*n + j以类似于二维数组的方式访问此向量,其中i是行索引,j是列索引,n是行的长度:
my_matrix[i*n + j];
Run Code Online (Sandbox Code Playgroud)
这与使用array [i] [j]访问2d数组相同.但是现在你有一个连续的内存块的优势,你不需要打扰新的/删除,你可以轻松地与功能共享和返回这个矢量对象.
我认为,在标准C ++中定义2D动态数组的方法都不能完全令人满意。
您最终不得不推出自己的解决方案。幸运的是,Boost中已经有了解决方案。boost :: multi_array:
#include "boost/multi_array.hpp"
template<typename T>
boost::multi_array<T, 2> create_array(int rows, int cols) {
auto dims = boost::extents[rows][cols];
return boost::multi_array<T, 2>(dims);
}
int main() {
auto array = create_array<int>(4, 3);
array[3][2] = 0;
}
Run Code Online (Sandbox Code Playgroud)
现场演示。