1. ホーム
  2. c++

[解決済み】C++で配列とstd::vectorの使い分け、性能の差は何?

2022-04-03 16:53:59

質問

C++のコースでは、新しいプロジェクトではもうC++の配列は使わないようにと言われています。私の知る限り、Stroustroup自身も配列を使用しないよう勧めています。しかし、パフォーマンスに大きな違いがあるのでしょうか?

どのように解決するのか?

C++の配列を使用し new (つまり、動的配列の使用)は避けるべきです。サイズを把握しなければならないという問題がありますし、手動で削除したり、いろいろと家計簿をつけなければなりません。

スタック上の配列を使うのもお勧めしません。範囲チェックができないし、配列を渡すとそのサイズに関する情報が失われるからです(配列からポインタへの変換)。そのため boost::array その場合、C++の配列を小さなクラスでラップし、そのクラスで提供される size 関数とそれを反復処理するイテレータがあります。

では std::vectorとC++のネイティブ配列の比較 (インターネットから引用)。

// Comparison of assembly code generated for basic indexing, dereferencing, 
// and increment operations on vectors and arrays/pointers.

// Assembly code was generated by gcc 4.1.0 invoked with  g++ -O3 -S  on a 
// x86_64-suse-linux machine.

#include <vector>

struct S
{
  int padding;

  std::vector<int> v;
  int * p;
  std::vector<int>::iterator i;
};

int pointer_index (S & s) { return s.p[3]; }
  // movq    32(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

int vector_index (S & s) { return s.v[3]; }
  // movq    8(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

// Conclusion: Indexing a vector is the same damn thing as indexing a pointer.

int pointer_deref (S & s) { return *s.p; }
  // movq    32(%rdi), %rax
  // movl    (%rax), %eax
  // ret

int iterator_deref (S & s) { return *s.i; }
  // movq    40(%rdi), %rax
  // movl    (%rax), %eax
  // ret

// Conclusion: Dereferencing a vector iterator is the same damn thing 
// as dereferencing a pointer.

void pointer_increment (S & s) { ++s.p; }
  // addq    $4, 32(%rdi)
  // ret

void iterator_increment (S & s) { ++s.i; }
  // addq    $4, 40(%rdi)
  // ret

// Conclusion: Incrementing a vector iterator is the same damn thing as 
// incrementing a pointer.

注意: 配列を new を割り当て、クラス以外のオブジェクト(例えば、プレーンな int ) またはユーザー定義のコンストラクタを持たないクラス を使用すると、要素が初期化されずに済みます。 new -割り当てられた配列は、パフォーマンス上の利点があります。 std::vector は、構築時にすべての要素をデフォルト値 (たとえば int は 0) に初期化します (気づかせてくれた @bernie に感謝します)。