web-dev-qa-db-ja.com

メモリ操作なしでC ++およびSTLで2D配列を定義するにはどうすればよいですか?

メモリ操作なしでC++およびSTLで2D配列を定義する方法はいくつかあり、次のコードは2つの異なる方法を示しています。

int main () 
{
    /**************
        1   2   3
        4   5   6
    ***************/
    // Method 1
    const int ROW = 2;
    const int COL = 3;
    int array1[ROW][COL];
    for(int i=0; i<ROW; i++)
        for(int j=0; j<COL; j++)
            array1[i][j] = i*COL+j+1;

    // Method 2
    typedef vector<vector<int> > ARRAY; 
    ARRAY array2;
    vector<int> rowvector;
    for(int i=0; i<ROW; i++)
    {
        rowvector.clear();
        for(int j=0; j<COL; j++)
            rowvector.Push_back(i*COL+j+1);
        array2.Push_back(rowvector);
    }
    return 0;
}

私の質問は:2D配列を定義する他の方法はありますか?どれが最も効率的ですか?ありがとう!

9
feelfree

2D配列を定義する他の方法はありますか?

明示的にメモリを操作せずにいいえ(malloc/free)。静的に割り当てられた配列(最初の例)を使用する場合、コンパイル時にスペースを割り当てるため、実行時に行または列を追加することはできません。

2番目の例では、動的メモリ割り当てを非表示にするstd::vectorを使用します。このようにして、最終的に実行時に行または列を追加できます。

配列の次元を動的に変更する必要がない場合、最初の解決策はより単純で高速なものです(std :: vectorの実装は静的配列に匹敵するほど高速で、よりエレガントでオブジェクト指向であると思いますが) )。

実行時に配列の次元を変更する必要がある場合は、std :: vectorを使用してください。これにより、mallocやfreeを直接処理する必要がなくなります。

4
Heisenbug

C++ 11では、std::arrayを使用します。

  std::array<std::array<int,3>,2> a {{
    {{1,2,3}},
    {{4,5,6}}
 }};

いくつかの使用法:

  a[0][2] = 13;
16
PiotrNycz

配列を定義する非常に効率的な方法の1つは、newおよびdelete演算子を使用した動的割り当てです。次に例を示します。

int **arr=new int*[ROW];
for( int i=0; i<ROW; ++i ) {
  arr[i] = new int[COL];
  for( int j=0; j<COL; ++j ) {
    arr[i][j] = some_val;
  }
}

このアプローチの大きな利点は、アレイが使用するメモリが不要になったときに、簡単に削除できることです。 2D配列を削除する例を次に示します。

for( int i=0; i<ROW; ++i ) {
  delete[] arr[i];
}
delete[] arr;   

一般的なパターンは、適切なインターフェイスを提供するクラス内に2D配列をカプセル化することです。その場合、たとえば_rows*cols_要素の単一のベクトルなど、他の内部表現を使用できます。インターフェイス(通常はoperator()(int,int)は、呼び出し元からの座標を線形ベクトル内の位置にマップします。

利点は、動的割り当てがありますが、単一の割り当て(各ベクトルが独自のメモリを取得する必要がある_std::vector<std::vector<int>>_とは異なり)と、データの局所性を提供する単一のブロックにあることです。

ここには多くのトレードオフがあります。

Cスタイルの2D配列int array[height][width]を宣言すると、実際には1つの連続したメモリブロックが得られます。コンパイラはインデックスを1Dアドレスに変換します

array[row][col] == *(array + row * width + col)
  • 利点:キャッシュコヒーレンシ。すべてのメモリは同じ場所にあります。
  • 短所:すべてのインデックス作成に乗算が必要です。間接参照の方が速い場合があります。

vectorvectorsを使用する場合、各行は個別に割り当てられます。外側のvectorは、内側のvectorsへのポインタを格納します。インデックス付けは間接参照になり、その後に追加が続きます。

array[row][col] == *(*(array + row) + col)
  • 利点:間接参照は乗算よりも高速な場合があります。
  • 短所:各行が個別に割り当てられるため、キャッシュコヒーレントではありません(実装がvector<vector>を最適化しない限り)。

パフォーマンスが本当に重要な場合は、両方をテストして、データでどちらが速いかを判断する必要があります。

6
japreiss

std::vectorを使用して2D配列を宣言するには、次のような構成を使用できます。

vector<vector<int> >  matrix( n, vector<int>(m, -1) );

これにより、サイズmatrixの2D配列nmで作成され、すべての要素が-1で初期化されます。

これは基本的に、 "値n"コンストラクターのvalアイテムで初期化するネストです。

vector (size_type n, const value_type& val,
                 const allocator_type& alloc = allocator_type());

(コンストラクター定義は ここ からコピーされました)

4
MatthewD

事前に要素を知っているなら、あなたはただすることができます

int arr [2] [3] = {{1,2、3}、{4、5、6}};

これは、method1およびmethod2よりも効率的であるはずです。ベクトルを使用すると、自分でメモリ操作を行うことはありませんが、ベクトルの実装ではおそらく動的に割り当てられた配列を使用します。

0
kkg