C++ 动态分配数组空间,以及opencv中Mat类的初始化

时间:2022-05-07 20:18:27

在C++中,如果想要申请动态数组,必须要用动态分配的方式。

int **matrix=new int*[num_of_rows];
for(int i=0;i<num_of_rows;i++){
int *row=new int[num_of_cols];
//在这里对这一行进行赋值
for(int j=0;j<num_of_cols;j++){
row[j]=j;
}
matrix[i]=row;
}

这样,就实现了一个二维数组空间的申请,以及赋值。
但是在实际使用中,可能会因为动态申请的空间过大,系统在申请空间时失败。此时会抛出Exception: fail to allocate memory block。那么,我们需要用一种方法告诉系统,如果申请空间失败,那就继续去申请,别来抛出异常。
C++ Dynamic Programming中,介绍了一种避免异常的方式,使用关键字:nothrow

int *foo = new (nothrow) int [5];

这样,在申请空间时,如果没有申请成功,new的返回值是null,如果申请成功,返回值是申请到的空间的指针。那么我们就可以通过if语句判断是否空间申请成功,然后告诉计算机如何执行。
于是我这样设计了申请数组的代码,如果没有申请成功,则一直去申请,直到申请成功为止:

int *mat = new (nothrow) int [1000];
while(!mat){
mat = new (nothrow) int [1000];
}
//程序如果能运行到这里,说明空间已经申请成功,可以对数据进行操作了
for(int i=0;i<1000;i++){
mat[i]=i;
}

C++ Dynamic Programming中说,这种方式是一种不太有效率的方法,但是简单有效。

Exception比较高效,但是在实际编程中,总是跳出Exception,好烦,索性设计成暴力申请空间的方式。这个问题有待深入研究,数据量大了,内存管理也是一门学问。

补充:最近做项目,用到opencv。Mat类有这个初始化函数:

Mat<T>(int rows, int cols,int type, T * data)

想要初始化Mat类型,可以通过数组实现。一种方式是对Mat的元素挨个进行赋值(方法一),另一种方式是将数组整体赋值(方法二)。还有一种貌似可行但实际不行的方法,也用的是二维数组(方法三)。
方法一:挨个赋值:

Mat mt(rows,cols,CV_32FC1);
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
mt.at<float>(i,j)=i*j;
}
}

方法二:利用数组整体赋值:

float *data =  new float[rows*cols];
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
data[i*cols+j]=i*j;
}
}
Mat mt(rows,cols,CV_32FC1,data);

方法三(不可行):利用不连续的数组空间进行Mat的初始化:

float **data = new float*[rows];
float *row;
for(int i=0;i<rows;i++){
row = new float[cols];
data=row;
}
//接下来进行二维数组的初始化
//此处省略若干代码

这种方式不可行的原因是,申请到的空间都是不连续的,可是Mat的初始化函数已经假定了第四个参数传来的数组空间是连续的。正是因为这个矛盾,导致使用第三种方式时,会报错,访问到无法访问的地址。

(方法三纠正)不过话说回来,如果是二维数组空间连续的话,还是可以通过这个二维数组进行Mat的初始化的(但是这样就不算是动态分配内存空间了,而是一开始就给定了固定大小的一块空间)。比如opencv的示例代码introduction_to_svm.cpp中:

// Set up training data
//! [setup1]
int labels[4] = {1, -1, -1, -1};
float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
//! [setup1]
//! [setup2]
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
Mat labelsMat(4, 1, CV_32SC1, labels);