1

そのため、std::array と boost::array (これらはほぼ同じであり、以降、あいまいに単に「配列」と呼ぶことにします) は、配列のコンテナー オブジェクトを提供するように設計されました。配列は動的にサイズを変更しません。ただし、どちらもコンストラクターのパラメーターとしてではなく、テンプレートの引数として配列サイズを取得することによって設計されています。結果: vector により、オブジェクトの作成後に動的にサイズ変更できます。array では、コンパイル時にサイズがわかっている必要があります。

私が見る限り、オブジェクトの作成時にサイズがわかっているがコンパイル時にはわからない配列がある場合、唯一のオプションは、1) vector を使用して余分なオーバーヘッドを不必要に発生させる、2) (non-コンテナー型) ネイティブ配列 (例: int foo[42];)、または 3) 独自の配列ラッパー クラスを最初から作成します。これは、ベクトルではなく配列を使用したいができない中間のケースであるということで正しいですか? または、配列が機能する可能性のある私ができる魔法はありますか?

理解に役立つ場合に備えて、この質問に影響を与えた理由について少し詳しく(わかりました、たくさん)以下に示します。

実行時にバイナリ データ (unsigned char[]、または配列) を繰り返し生成し、それを別のモジュール (呼び出し先など) に渡すモジュールがあります (呼び出し元など)。呼び出し先モジュールは配列を変更しません (コピーを作成し、必要に応じてそれを変更します)。そのため、呼び出し元モジュールが最初に配列を作成すると、サイズは変更されません (内容も変更されません)。ただし、2 つの問題が発生します。1) 呼び出し元は、配列が生成されるたびに同じサイズの配列を生成しない場合があります。呼び出し元は、配列を作成する実行時に配列サイズを認識しますが、コンパイル時には認識しません。2) 呼び出し元が配列を呼び出し先に渡すメソッドは、呼び出し元が渡す任意のサイズの配列を取得できる必要があります。

テンプレート関数にすることを考えました。

template<size_t N> void foo(const array<unsigned char, N>& my_array);

ただし、呼び出し先モジュールの実装からインターフェイスを分離するために、インターフェイス クラスを使用しています。したがって、関数は、テンプレート化と相互に排他的な仮想メソッドである必要があります。さらに、それが問題にならなかったとしても、上記の #1 と同じ問題が残ります。コンパイル時に配列のサイズがわからない場合、コンパイル時にテンプレート化された関数を解決することもできません。

私の実際の機能:

virtual void foo(const array<unsigned char, N>& my_array); // but what is N???

要約すると、私の唯一の本当の選択肢は、ベクトルまたはネイティブ配列を使用することです。たとえば、

virtual void foo(const vector<unsigned char> my_array); // unnecessary overhead
virtual void foo(const unsigned char[] my_array, size_t my_array_len); // yuk

または、std::array または boost::array を使用できるようにする、見落としているトリックがありますか?

4

3 に答える 3

4

C++11 になるまではstd::dynarray、以下を使用できますstd::unique_ptr

std::unique_ptr<Foo[]> arr(new Foo[100]);

arr[0]これを、arr[1]などとして使用できdelete[]、破壊時に正しいものを呼び出します。オーバーヘッドは最小限です (ポインタのみ)。

配列型の一意のポインターとの唯一の違いはstd::dynarray、後者にはイテレーターやsizeその他の「コンテナー」プロパティがあり、「一般的なユーティリティ」ではなく「コンテナー」セクションにあることだと思います。[更新:また、コンパイラは、スタック ストレージを使用するために、それをネイティブにサポートdynarrayおよび最適化することを選択する場合があります。]

于 2013-07-09T23:43:06.090 に答える
1

コンパイル時に長さが分からない場合は、どの形式の std::array も使用できません。

コンパイル時に配列のサイズがわからない場合は、std::vector の使用を真剣に検討してください。可変長配列 ( などint foo[n]) の使用は標準の C++ ではなく、指定された長さが十分に大きい場合にスタック オーバーフローが発生します。また、std::vector よりもオーバーヘッドが (かなり) 少ない配列のようなラッパーを作成することはできません。

私はただ使うだろう

virtual void foo(const unsigned char* my_array, size_t my_array_len);

そして、それを次のように呼び出します

obj.foo(&vec[0], vec.size());

オーバーヘッドはなく、必要なことを実行します。通常の配列 ( int foo[42]) に加えて、これはベクトルおよび std::array でオーバーヘッドなしで呼び出すこともできます。

于 2013-07-10T00:03:35.990 に答える
0

その他の考慮事項:

  • 配列はスタックに割り当てられます。これは、ヒープに割り当てるよりもはるかに高速です。
  • 配列は、作成時に常にすべての要素を初期化します。

そう:

    class Foo;
    std::array<Foo, 100> aFoo;

100 個のオブジェクトを構築します ( 100 回Foo呼び出します)。Foo::Foo()

    std::vector<Foo> vFoo;
    vFoo.reserve(100);

(ヒープ上に) 100 個のFooオブジェクト用のスペースを確保しますが、それらのいずれも構築しません。

于 2013-07-10T00:44:24.050 に答える