web-dev-qa-db-ja.com

std :: arrayを使用して独自の配列クラスを作成する特定の理由?

_std::array_を使用して独自の配列を作成する必要がある特定の条件または要件は何ですか?

これが私の背景です:

私は、少数の人々が使用するうまくいけばをベースにした小さなシンプルなライブラリを開発しています。現在の構造では、iteratorsを使用して_std::vector_と_std::array_の両方を使用できますが、多くの人は_std::array_を使用するのが嫌で、使用するように見えず、表記がわかりにくい場合がありますライブラリを操作します。

私は自分のライブラリを_std::array_でより良く機能するように試みましたが、おそらく自分で自分のものを提供し、必要な機能を追加する必要があると思いました。

例:library::array<int, 2> myArray; myArray.fill(1, 100);と私は、特にtemplatesと他のsortingアルゴリズムで、自分のスキルを伸ばすための良いプロジェクトになると思いました。

5
Phorce

  • いくつの次元が必要ですか?
    • C++テンプレートプログラミングでは、高次元の各レベルでコードの重複が必要になる場合があります。
    • 住所計算は簡単な部分です。単純なアプローチは、最大12のディメンションに使用できます。
    • 3次元の例:
      • 配列のサイズを[m, n, p]にします
      • 各次元について、項を連続的に乗算することにより「重みベクトル」を計算します。
        [p*n, p, 1]
      • [i, j, k]の要素にアクセスするには、その線形化された要素のインデックスを次のように計算できます。
        [i, j, k] dotproduct [p*n, p, 1]
        または((((i * n) + j) * p) + k)
    • 高次元の場合、要素アドレスの計算に必要な乗算に費やされる時間を減らすように注意する必要があります。

  • 配列の一般的なサイズは何ですか、桁違いですか?
    • 小規模な配列(1000要素未満)の場合、プロファイラーによって別の方法で証明されない限り、基本的にすべての設計と実装が機能します。
    • 中規模のアレイの場合(コンピューターのメモリまたはアプリケーションのアドレス空間に完全に収まる限り)、パフォーマンスはますます重要な問題になります。
    • 大きな配列(連続したメモリの一部としては適合できない)の場合、アーキテクチャの問題が優先されます。

  • アーキテクチャ/メモリレイアウト
    • 駆動力:
      • サイズ/スケール
      • パフォーマンス
      • 計算プラットフォーム
      • 相互運用性(他のコード/ライブラリと)
      • アクセスセマンティクス
    • 利用可能な選択肢:
      • 連続メモリ(最も簡単で簡単な選択)
      • 非連続メモリ(例:タイル配列)
      • メモリマップファイル
      • ネットワーク内の複数のマシンに分散

  • 実装は高パフォーマンスをサポートする必要がありますか?
    • 基本的に、1秒あたり10億回以上の基本操作が必要なものは、デザインを選択する目的で高性能と見なすことができます。
    • 高性能を実現するように設計すると、以下に制約が課されます。
      • 計算プラットフォームの選択
      • メモリレイアウトの選択

  • 計算プラットフォーム?
    • 高いパフォーマンスが必要ない場合は、スカラーC++コードで十分です。
    • それ以外の場合は、高性能の計算プラットフォームが必要になります。
    • これは以下に制約を課します:
      • メモリレイアウトの選択
    • 計算上の選択
      • スカラーC++
      • マルチコアコンピューティング
      • 手動スレッディング
      • 並行プログラミングライブラリ(Intel TBB、Microsoft PPL/AMP)
      • コンパイラー支援(OpenMP)
      • 並列プログラミング言語。例:シルク、ブルック
      • Open-Soureライブラリ(OpenCV)
      • SIMD(単一命令複数データ)の例:Intel SSE2、AVX、ARM NEON、PowerPC AltiVec
      • GPUプログラミング(CUDA、OpenCL)

  • 配列は他のライブラリからアクセス可能、コピーせずに である必要がありますか?
    • その場合、配列のmemory layoutは、使用している他のライブラリと互換性がある必要があります。
    • 配列サイズが小さい場合、または書き込み(変更)が頻繁に発生するアクセスパターンの場合、コピーは問題になりません。
    • 非常に頻繁に読み書きされる大規模なアレイの場合、データのコピーがパフォーマンスの問題になる可能性があります。

  • データのコピーとアクセスのセマンティクスの不適切な組み合わせが、ますます不均衡なパフォーマンスの問題を引き起こす可能性があるストーリー:
    • それぞれが100 MBアレイの独自のコピーを持ち、定期的に同期を維持する必要がある2つのモジュールについて考えてみます。
    • モジュールの1つが配列のどの領域が変更されているかを追跡することなく、自身のコピーを自由に変更するとします
    • 同期を実行する時間になると、最初のモジュールは100 MBアレイ全体をコピーする必要があります。これは、同期が必要な部分を判別できないためです。
    • 最初のモジュールのユーザーは、「この配列のいくつかの要素のみを変更する場合、ライブラリの同期に時間がかかるのはなぜですか?」
  • レッスン:API呼び出しを行うために変更を要求することにより、アクセスセマンティクスを使用して、データコピーの非効率性を減らすことができます。

  • アクセスセマンティクス
    • 3つの質問に要約します。
      • 要素のメモリアドレスを計算するのは誰ですか?添え字(i, j, k)を指定
      • アレイの寿命(所有権)はどのように管理されますか?
      • 配列の実装は配列のどの部分が変更されたか通知されますか?
  • 選択肢:
    • 基礎となるメモリへの直接アクセス、API呼び出しなし。
      • 配列の実装では、配列のどの部分が変更または使用されているかがわかりません。
    • 基になるメモリへの直接アクセス。配列ビューをロック/ロック解除するためのAPI呼び出しが必要です。
      • アクセス制御を強制できないため、「アドバイザリロック」と呼ばれます。
      • ライブラリをロック/ロック解除することにより、アレイの現在のユーザーと変更中の領域が通知されるため、アドバイザリロックも役立ちます。
    • 一度に1つの要素を読み書きするAPIメソッド
      • 実装と使用が最も簡単
      • 最も遅い
    • 一度に配列ビューをコピーするためのAPIメソッド
      • 配列のサブ長方形と通常のC/C++/Java配列の間のコピー
      • 高性能と安全性のバランスが良い
      • アレイの実装で別のメモリレイアウトを使用できます

  • ライブラリインターフェイスと構文の設計
    • ...

おめでとうございます。インターフェースと構文の設計を始めることができます。

14
rwong

私はあなたのライブラリは一般的なものであり、絶対に必要な場合を除いて、ベクトル/配列型に結び付けられてはならないものだと思います。汎用性はイテレーターによって提供されます-イテレーターはアルゴリズムとコンテナー間のインターフェースです。

インターフェースを見てください C++アルゴリズムが提供する 。与えられたアルゴリズムは、特定のプロパティを持ついくつかの反復子を必要とするだけです。コンテナがそのようなイテレータを提供している限り、アルゴリズムはコンテナ自体を気にしません。

イテレータの観点から考えると、std::arrayおよびstd::vector動作は同じです。どちらにも順方向および逆方向のランダムアクセス反復子があります。アルゴリズムがそのような反復子を使用できる場合は、両方で使用できますstd::arrayおよびstd::vector

インターフェースとしてイテレーターを使用しているとは私はよく思いません。そうした場合、イテレーターの元になるコンテナーのタイプがインターフェースのどこにも表示されないためです。まあ、明示的にstd::array<T>::iterator-それは確かに非常に悪いスタイルになるでしょう。

6

ライブラリから独自の配列クラスを提供する唯一の理由は、現在提供されているもの(std::arraystd::vectorおよびraw配列)が要件に適合しない場合です。たとえば、動的割り当てなしで境界チェックを実行する配列が必要な場合は、std::arrayを導入する前に自分でそれを記述する必要がありました。

ライブラリでの配列クラスの受け入れに関する限り、std::arrayはC++言語へのかなり新しい追加であり、独自の配列クラスを持つ既存のライブラリのヒープがあることを理解する必要があります。
ライブラリをより速く受け入れるには、有用な機能を提供することに加えて、少なくともすべての配列のような型の最も低い共通の特徴、つまり単純なポインタを受け入れる必要があります。