天天看點

C++ 動态配置設定數組空間,以及opencv中Mat類的初始化

在C++中,如果想要申請動态數組,必須要用動态配置設定的方式。

int **matrix=new int*[num_of_rows];
for(int i=;i<num_of_rows;i++){
    int *row=new int[num_of_cols];
    //在這裡對這一行進行指派
    for(int j=;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 [];
           

這樣,在申請空間時,如果沒有申請成功,new的傳回值是null,如果申請成功,傳回值是申請到的空間的指針。那麼我們就可以通過if語句判斷是否空間申請成功,然後告訴計算機如何執行。

于是我這樣設計了申請數組的代碼,如果沒有申請成功,則一直去申請,直到申請成功為止:

int *mat = new (nothrow) int [];
while(!mat){
    mat = new (nothrow) int [];
}
//程式如果能運作到這裡,說明空間已經申請成功,可以對資料進行操作了
for(int i=;i<;i++){
    mat[i]=i;
}
           

C++ Dynamic Programming中說,這種方式是一種不太有效率的方法,但是簡單有效。

Exception比較高效,但是在實際程式設計中,總是跳出Exception,好煩,索性設計成暴力申請空間的方式。這個問題有待深入研究,資料量大了,記憶體管理也是一門學問。

補充:最近做項目,用到opencv。Mat類有這個初始化函數:

想要初始化Mat類型,可以通過數組實作。一種方式是對Mat的元素挨個進行指派(方法一),另一種方式是将數組整體指派(方法二)。還有一種貌似可行但實際不行的方法,也用的是二維數組(方法三)。

方法一:挨個指派:

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

方法二:利用數組整體指派:

float *data =  new float[rows*cols];
for(int i=;i<rows;i++){
    for(int j=;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=;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);
           

繼續閱讀