std::list
とstd::vector
が存在するため、C++ で従来の C 配列を使用する理由はありますかmalloc
?
11 に答える
が利用可能なC++ 11std::array
では、答えは「はい、配列は避けるべきです」です。C++11 より前では、C 配列を使用して、配列を自動ストレージ (つまり、スタック) に割り当てる必要がある場合があります。
確かに、std::array
C++11 ではありますが、実際には静的データのみです。C スタイルの配列には、次の 3 つの重要な利点があり
std::vector
ます。
動的割り当ては必要ありません。このため、非常に小さな配列が多数ある可能性が高い場合は、C スタイルの配列を使用することをお勧めします。n 次元の点のようなことを言います:
template <typename T, int dims> class Point { T myData[dims]; // ... };
通常、 a は
dims
非常に小さく (2 つまたは 3 つ)、T
組み込み型 (double
) であり、std::vector<Point>
何百万もの要素になる可能性があると想像できます。3 double の何百万もの動的割り当ては絶対に必要ありません。サポート静的初期化。これは、次のような静的データのみの問題です。
struct Data { int i; char const* s; }; Data const ourData[] = { { 1, "one" }, { 2, "two" }, // ... };
これは、初期化の問題のすべての順序を
std::string
回避するため、ベクター (および ) を使用するよりも望ましいことがよくあります。実際のコードを実行する前に、データがプリロードされます。最後に、上記に関連して、コンパイラは初期化子から配列の実際のサイズを計算できます。それらを数える必要はありません。
C++11 にアクセスできる場合はstd::array
、最初の 2 つの問題が解決されます。最初のケースでは、C スタイルの配列よりも優先して使用する必要があります。ただし、3 つ目の問題には対応していません。初期化子の数に応じてコンパイラが配列を次元化することは、C スタイルの配列を優先する正当な理由です。
「決して」とは言いませんが、STL の真のデータ構造によって、それらの役割が大幅に減少することに同意します。
また、オブジェクト内にカプセル化することで、このような選択の影響を最小限に抑える必要があるとも言えます。配列がプライベート データ メンバーである場合は、クラスのクライアントに影響を与えずにスワップ インまたはスワップ アウトできます。
私は、動的メモリ割り当てを使用できない安全性が重要なシステムに取り組んできました。メモリは常にスタック上にある必要があります。したがって、この場合、サイズはコンパイル時に固定されるため、配列を使用します。
array
inは、動的サイズのとc++
の固定サイズの高速な代替手段を提供します。std::arrayは の追加機能の 1 つです。C スタイルの配列の集約型セマンティクスを提供しながら、std コンテナーの利点を提供します。std::vector
std::list
c++11
したがって、必要な場合は、ベクターよりも をc++11
使用します。std::array
しかし、Cスタイルの配列は避けたいと思いC++03
ます。
ほとんどの場合、いいえ、生の配列を使用する理由が思いつきませんvectors
。コードが新しい場合。
配列と生のポインタを期待するコードとライブラリが互換性を持つ必要がある場合は、配列を使用する必要があるかもしれません。
多くの人が、スタックに配列を割り当てるための std::array と、ヒープのための std::vector を指摘していることを知っています。しかし、どちらも非ネイティブ アラインメントをサポートしていないようです。SSE または VPX 命令を使用する任意の種類の数値コードを実行している場合 (したがって、それぞれ 128 または 256 バイトのアラインメントが必要です)、C 配列が最善の策のようです。
少量の静的なデータを格納しているのであれば、配列は依然として有用であると言えます。
std::vector
私が考えることができる配列(もちろん、必要に応じて自動的に解放を管理するものにラップされている)の唯一の利点は、vector
コンパイラがC++ 11をサポートしてコンストラクタを移動しない限り、そのデータの所有権を渡すことができないことです。
C スタイルの配列は基本的なデータ構造なので、使用した方がよい場合もあります。ただし、一般的なケースでは、基になるデータの角を丸くする、より高度なデータ構造を使用します。C++ を使用すると、メモリを使用して非常に興味深く便利なことを行うことができます。その多くは、単純な配列で機能します。
内部で STL コンテナーを使用する必要がありますが、異なるモジュール間でそのようなコンテナーへのポインターを渡すべきではありません。そうしないと、依存地獄に陥ります。例:
std::string foo;
// fill foo with stuff
myExternalOutputProc(foo.c_str());
非常に良い解決策ですが、そうではありません
std::string foo;
// fill foo with stuff
myExternalOutputProc(&foo);
その理由は、std::string はさまざまな方法で実装できるためですが、C スタイルの文字列は常に C スタイルの文字列です。