web-dev-qa-db-ja.com

Cスタイルの配列からstd :: vectorを初期化する方法は?

Cスタイルの配列からstd::vectorを初期化する最も安価な方法は何ですか?

例:次のクラスにはvectorがありますが、外部の制限により、データはCスタイルの配列として渡されます。

class Foo {
  std::vector<double> w_;
public:
  void set_data(double* w, int len){
   // how to cheaply initialize the std::vector?
}

明らかに、w_.resize()を呼び出してから要素をループするか、std::copy()を呼び出すことができます。より良い方法はありますか?

148
Frank

ポインタをイテレータとして扱うことができることを忘れないでください:

w_.assign(w, w + len);
209
Pavel Minaev

Wordの初期化を使用するため、これが1回限りの割り当てなのか、複数回発生する可能性があるのか​​が不明確です。

一度だけの初期化が必要な場合は、コンストラクターに入れて、2つのイテレーターベクトルコンストラクターを使用できます。

Foo::Foo(double* w, int len) : w_(w, w + len) { }

それ以外の場合は、以前に提案されたとおりにassignを使用します。

void set_data(double* w, int len)
{
    w_.assign(w, w + len);
}
37
Mark B

まあ、Pavelは近かったのですが、Cスタイルの配列からシーケンシャルコンテナを初期化する、よりシンプルでエレガントなソリューションがあります。

あなたの場合:

w_ (array, std::end(array))
  • arrayは配列の先頭へのポインタを取得します(名前をキャッチしませんでした)。
  • std :: end(array)は、配列の最後へのイテレータを取得します。
11
Mugurel

配列のサイズを自動的に「学習」できます。

template<typename T, size_t N>
void set_data(const T (&w)[N]){
    w_.assign(w, w+N);
}

うまくいけば、上記のようにインターフェイスをset_dataに変更できます。最初の引数としてCスタイルの配列を受け入れます。それはたまたま参照によってそれを取る。


仕組み

[更新:サイズの学習に関するより包括的な議論については here を参照]

より一般的なソリューションは次のとおりです。

template<typename T, size_t N>
void copy_from_array(vector<T> &target_vector, const T (&source_array)[N]) {
    target_vector.assign(source_array, source_array+N);
}

これは、配列が配列への参照として渡されるため機能します。 C/C++では、配列を関数として渡すことはできません。代わりに、ポインターに減衰し、サイズを失います。しかし、C++では、canは配列への参照を渡すことができます。

配列を参照で渡すには、型が正確に一致する必要があります。配列のサイズはそのタイプの一部です。これは、テンプレートパラメータNを使用してサイズを学習できることを意味します。

ベクトルを返すこの関数を使用する方が簡単かもしれません。適切なコンパイラー最適化が有効になっていると、これは見た目よりも速くなるはずです。

template<typename T, size_t N>
vector<T> convert_array_to_vector(const T (&source_array)[N]) {
    return vector<T>(source_array, source_array+N);
}
9
Aaron McDaid

std::vector<double>::assignは、小さなコードであるため、進むべき方法です。しかし、実際にはどのように機能しますか?サイズを変更してからコピーしませんか? STLのMS実装では、まさにそのように使用しています。

std::vectorを初期化(再)するための高速な方法はありませんがあると思います。

0
Janusz Lenar