2012-08-17 56 views
0

有一個功能,接受2D陣列:傳遞RAII結構爲2D陣列成一個函數

void foo (double ** p) 
{ /*writing some data into p*/ } 

我不希望原始2D陣列傳遞到該功能,因爲我不想管理內存調用newdelete。我也不想將功能簽名更改爲void foo (std::vector< std::vector<double> >&)。我不能將foo作爲模板函數(在我的項目中它是一個COM接口方法)。

我想通過一些RAII對象的除芯生的,一個像

void foo (double * p){} 
std::vectore<double> v(10); 
p(&v[0]); 

有沒有辦法爲二維數組做到這一點?我試圖

std::vector< std::vector<int> > v; 
foo(&v[0][0]) 

std::vector< std::tr1::shared_ptr<int> > v; 

,但我得到的編譯錯誤error C2664 - cannot convert parameter

另外,在這種情況下,可以確定函數內的原始地址算術工作正常嗎?

沒有C++ 11,2D陣列的大小是已知的。

回答

1

一個可行的辦法是改變:

std::vector< std::vector<int> > v; 
foo(&v[0][0]) 

std::vector< std::vector<int> > v; 
std::vector<int*> v_ptr; 
for (...) { 
    v_ptr[i] = &v[i][0]; 
} 
foo(&v_ptr[0]) 
+0

謝謝,至少我的編譯器沒有錯誤地處理它!我想知道,能否確定在''foo''中使用地址算術? – fogbit 2012-08-17 12:29:52

+0

@fogbit是的,這應該沒問題 – 2012-08-17 12:59:24

1

儘管安德烈亞斯已經作出了回答你的問題可以解決您的具體問題,我想指出的是,雖然那是有效的,這可能不是你想要做的。

由於您正在使用C++(而不是一種更容易使用的語言),我假設您關心性能。在這種情況下,您的方法很可能從一開始就是錯誤的,因爲double**表示陣列(或者更確切地說可以表示)而不是二維陣列。爲什麼這不好?因爲,與std::vector< std::vector<int> >示例一樣,需要多次分配,並且生成的內存不連續(這對緩存不利),這與double array[N][M]不同。

對於2D數組,您實際上應該使用帶有索引計算的1D數組,這對緩存更友好。這當然不允許使用[x][y]式索引(取而代之,您必須使用[x+N*y][y+M*x],這取決於您選擇的「Fortran順序」還是「C順序」),但是可以避免緩存問題並且只需要一次分配(並且簡單double*指針)。

如果您遍歷數組中的所有元素以

for(unsigned x = 0; x < N; ++x) for(unsigned y = 0; y < M; ++y) 
{ 
    unsigned idx = y + M * x; 
    p[idx] = bar(x, y); // equivalent to p[x][y] = bar(x,y) in the array-of-arrays case 
} 

你甚至可以避開乘法,因爲這基本上是一維迭代額外的代2D的指數

for(unsigned x = 0, idx = 0; x < N; ++x) for(unsigned y = 0; y < M; ++y, ++idx) 
{ 
    p[idx] = bar(x, y); 
}