web-dev-qa-db-ja.com

ハードコードされた要素でstd :: vectorを初期化するための最も簡単な方法は何ですか?

配列を作成して初期化することができます:

int a[] = {10, 20, 30};

どうやってstd::vectorを作成し、それを同じようにエレガントに初期化するのですか?

私が知っている最善の方法は次のとおりです。

std::vector<int> ints;

ints.Push_back(10);
ints.Push_back(20);
ints.Push_back(30);

もっと良い方法はありますか?

557
Agnel Kurian

1つの方法は、配列を使ってベクトルを初期化することです。

static const int arr[] = {16,2,77,29};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
513
Yacoby

コンパイラがC++ 11をサポートしている場合は、次のようにします。

std::vector<int> v = {1, 2, 3, 4};

これはGCCで利用可能です バージョン4.4以降 。残念ながら、VC++ 2010はこの点で遅れているようです。

あるいは、 Boost.Assign ライブラリは、次のことを可能にするために非マクロマジックを使用します。

#include <boost/assign/list_of.hpp>
...
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);

または

#include <boost/assign/std/vector.hpp>
using namespace boost::assign;
...
std::vector<int> v;
v += 1, 2, 3, 4;

しかし、これにはいくらかのオーバーヘッドがあることに注意してください(基本的に、list_ofは内部的にstd::dequeを作成します)。そのため、パフォーマンス重視のコードでは、Yacobyが言うようにしたほうがよいでしょう。

578
Manuel

C++ 0xでは、配列で行ったのと同じ方法でそれを実行できますが、現在の標準ではそうではありません。

言語サポートだけであなたは使うことができます:

int tmp[] = { 10, 20, 30 };
std::vector<int> v( tmp, tmp+3 ); // use some utility to avoid hardcoding the size here

他のライブラリを追加することができればboost :: assignmentを試すことができます。

vector<int> v = list_of(10)(20)(30);

配列のサイズがハードコーディングされないようにするには

// option 1, typesafe, not a compile time constant
template <typename T, std::size_t N>
inline std::size_t size_of_array( T (&)[N] ) {
   return N;
}
// option 2, not typesafe, compile time constant
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))

// option 3, typesafe, compile time constant
template <typename T, std::size_t N>
char (&sizeof_array( T(&)[N] ))[N];    // declared, undefined
#define ARRAY_SIZE(x) sizeof(sizeof_array(x))

可能であれば、最新のC++ [11,14,17、...]の方法を使用してください。

std::vector<int> vec = {10,20,30};

可変長配列をループ処理したりsizeof()を使ったりするという古い方法は、目には本当にひどく、精神的なオーバーヘッドの観点からはまったく不要です。やあ.

70
Adam Erickson

C++ 11の場合:

#include <vector>
using std::vector;
...
vector<int> vec1 { 10, 20, 30 };
// or
vector<int> vec2 = { 10, 20, 30 };

Boost list_ofを使う:

#include <vector>
#include <boost/assign/list_of.hpp>
using std::vector;
...
vector<int> vec = boost::assign::list_of(10)(20)(30);

ブーストアサインを使用する:

#include <vector>
#include <boost/assign/std/vector.hpp>
using std::vector;
...
vector<int> vec;
vec += 10, 20, 30;

従来のSTL:

#include <vector>
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );

汎用マクロを使った従来のSTL

#include <vector>
#define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0])
#define ARRAY_END(ar) (ar + ARRAY_SIZE(ar))
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec (arr, ARRAY_END(arr));

ベクトル初期化マクロを使った従来のSTL

#include <vector>
#define INIT_FROM_ARRAY(ar) (ar, ar + sizeof(ar) / sizeof(ar[0])
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec INIT_FROM_ARRAY(arr);
56
mbells

ちょうど私が私の0.02ドルで投げたいと思った。私はこれを宣言する傾向があります。

template< typename T, size_t N >
std::vector<T> makeVector( const T (&data)[N] )
{
    return std::vector<T>(data, data+N);
}

どこかのユーティリティヘッダで、それから必要なのは以下のとおりです。

const double values[] = { 2.0, 1.0, 42.0, -7 };
std::vector<double> array = makeVector(values);

しかし、私はC++ 0xを待つことができません。私のコードもVisual Studioでコンパイルする必要があるので、動けなくなります。ブー。

51
M. Tibbits

C++ 11より前のバージョン:

方法1 =>

vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
vector<int>v;

方法2 =>

 v.Push_back(SomeValue);

以下のC++ 11以降も可能です

vector<int>v = {1, 3, 5, 7};
34
A J

で始まります:

int a[] = {10, 20, 30}; //i'm assuming a is just a placeholder

C++ 11コンパイラを持っておらず、boostを使いたくない場合

const int a[] = {10, 20, 30};
const std::vector<int> ints(a,a+sizeof(a)/sizeof(int)); //make it const if you can

C++ 11コンパイラがなく、boostを使うことができるなら:

#include <boost/assign.hpp>
const std::vector<int> ints = boost::assign::list_of(10)(20)(30);

C++ 11コンパイラをお持ちの場合

const std::vector<int> ints = {10,20,30};
27
Carl

最も簡単な方法は次のとおりです。

vector<int> ints = {10, 20, 30};
21
Paul Baltescu

ベクトル初期化用 -

vector<int> v = {10,20,30}

c ++ 11コンパイラがあれば実行できます。

それ以外の場合は、データの配列を取得してからforループを使用できます。

int array[] = {10,20,30}
for(unsigned int i=0; i<sizeof(array)/sizeof(array[0]); i++)
{
     v.Push_back(array[i]);
}

これら以外にも、上記のコードを使用したさまざまな方法があります。私の意見では、これらの方法は覚えやすく、書くのが簡単です。

19
Tush_08

コンパイラが Variadicマクロ をサポートしている場合(これは最近のほとんどのコンパイラに当てはまります)、次のマクロを使用してベクトル初期化をワンライナーに変えることができます。

#define INIT_VECTOR(type, name, ...) \
static const type name##_a[] = __VA_ARGS__; \
vector<type> name(name##_a, name##_a + sizeof(name##_a) / sizeof(*name##_a))

このマクロを使えば、次のようなコードで初期化ベクトルを定義できます。

INIT_VECTOR(int, my_vector, {1, 2, 3, 4});

これにより、要素1、2、3、4を持つmy_vectorという名前の整数の新しいベクトルが作成されます。

14
Matt Ball

C++ 11の場合:

static const int a[] = {10, 20, 30};
vector<int> vec (begin(a), end(a));
11
BufBills

Boostを使用したくないが、以下のような構文を楽しみたい場合

std::vector<int> v;
v+=1,2,3,4,5;

このコードを含める

template <class T> class vector_inserter{
public:
    std::vector<T>& v;
    vector_inserter(std::vector<T>& v):v(v){}
    vector_inserter& operator,(const T& val){v.Push_back(val);return *this;}
};
template <class T> vector_inserter<T> operator+=(std::vector<T>& v,const T& x){
    return vector_inserter<T>(v),x;
}
11

私はva_argを使って私自身のソリューションを構築します。このソリューションはC98に準拠しています。

#include <cstdarg>
#include <iostream>
#include <vector>

template <typename T>
std::vector<T> initVector (int len, ...)
{
  std::vector<T> v;
  va_list vl;
  va_start(vl, len);
  for (int i = 0; i < len; ++i)
    v.Push_back(va_arg(vl, T));
  va_end(vl);
  return v;
}

int main ()
{
  std::vector<int> v = initVector<int> (7,702,422,631,834,892,104,772);
  for (std::vector<int>::const_iterator it = v.begin() ; it != v.end(); ++it)
    std::cout << *it << std::endl;
  return 0;
}

デモ

11
aloisdg

もっと最近の重複した質問は この答え by Viktor Sehr を持っています。私にとっては、それはコンパクトで、視覚的に魅力的で(あなたが値を「押し込んでいる」ように見えます)、c ++ 11やサードパーティのモジュールを必要とせず、余分な(書かれた)変数の使用を避けます。以下は私がいくつかの変更を加えてそれを使っている方法です。将来的にはvectorやva_argの機能拡張に切り替えるかもしれません。


// Based on answer by "Viktor Sehr" on Stack Overflow
// https://stackoverflow.com/a/8907356
//
template <typename T>
class mkvec {
public:
    typedef mkvec<T> my_type;
    my_type& operator<< (const T& val) {
        data_.Push_back(val);
        return *this;
    }
    my_type& operator<< (const std::vector<T>& inVector) {
        this->data_.reserve(this->data_.size() + inVector.size());
        this->data_.insert(this->data_.end(), inVector.begin(), inVector.end());
        return *this;
    }
    operator std::vector<T>() const {
        return data_;
    }
private:
    std::vector<T> data_;
};

std::vector<int32_t>    vec1;
std::vector<int32_t>    vec2;

vec1 = mkvec<int32_t>() << 5 << 8 << 19 << 79;  
// vec1 = (5,8,19,79)
vec2 = mkvec<int32_t>() << 1 << 2 << 3 << vec1 << 10 << 11 << 12;  
// vec2 = (1,2,3,5,8,19,79,10,11,12)
10
Othermusketeer

あなたはboost :: assignを使ってそれを行うことができます。

vector<int> values;  
values += 1,2,3,4,5,6,7,8,9;

詳細はこちら

10
f4.

以下の方法はc ++でベクトルを初期化するために使用することができます。

  1. int arr[] = {1, 3, 5, 6}; vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));

  2. vector<int>v; v.Push_back(1); v.Push_back(2); v.Push_back(3);など

  3. vector<int>v = {1, 3, 5, 7};

3番目のものはC++ 11以降でのみ許されます。

6
Jay

Boostへの依存関係を作り出さずにBoost :: assignと同じ一般的な順序で何かが欲しいなら、以下は少なくとも漠然と似ています:

template<class T>
class make_vector {
    std::vector<T> data;
public:
    make_vector(T const &val) { 
        data.Push_back(val);
    }

    make_vector<T> &operator,(T const &t) {
        data.Push_back(t);
        return *this;
    }

    operator std::vector<T>() { return data; }
};

template<class T> 
make_vector<T> makeVect(T const &t) { 
    return make_vector<T>(t);
}

それを使用するための構文がきれいになってほしいのですが、それでも特にひどいわけではありません。

std::vector<int> x = (makeVect(1), 2, 3, 4);
4
Jerry Coffin

配列が

int arr[] = {1, 2, 3};
int len = (sizeof(arr)/sizeof(arr[0])); // finding length of array
vector < int > v;
std:: v.assign(arr, arr+len); // assigning elements from array to vector 
4
Fake_Death
// Before C++11
// I used following methods:

// 1.
int A[] = {10, 20, 30};                              // original array A

unsigned sizeOfA = sizeof(A)/sizeof(A[0]);           // calculate the number of elements

                                                     // declare vector vArrayA,
std::vector<int> vArrayA(sizeOfA);                   // make room for all
                                                     // array A integers
                                                     // and initialize them to 0 

for(unsigned i=0; i<sizeOfA; i++)
    vArrayA[i] = A[i];                               // initialize vector vArrayA


//2.
int B[] = {40, 50, 60, 70};                          // original array B

std::vector<int> vArrayB;                            // declare vector vArrayB
for (unsigned i=0; i<sizeof(B)/sizeof(B[0]); i++)
    vArrayB.Push_back(B[i]);                         // initialize vArrayB

//3.
int C[] = {1, 2, 3, 4};                              // original array C

std::vector<int> vArrayC;                            // create an empty vector vArrayC
vArrayC.resize(sizeof(C)/sizeof(C[0]));              // enlarging the number of 
                                                     // contained elements
for (unsigned i=0; i<sizeof(C)/sizeof(C[0]); i++)
     vArrayC.at(i) = C[i];                           // initialize vArrayC


// A Note:
// Above methods will work well for complex arrays
// with structures as its elements.
4
sg7
typedef std::vector<int> arr;

arr a {10, 20, 30};       // This would be how you initialize while defining

コンパイルするには:

clang++ -std=c++11 -stdlib=libc++  <filename.cpp>
4
shaveenk

ここにたくさんの良い答えがあります、しかし、私はこれを読む前に私が独自に私のところに到着したので、私はとにかくここで私のものを捨てることにしました...

これが私がこのために使っている方法で、コンパイラやプラットフォームを越えて普遍的に機能します。

オブジェクトのコレクションのコンテナとして構造体またはクラスを作成します。 <<の演算子オーバーロード関数を定義します。

class MyObject;

struct MyObjectList
{
    std::list<MyObject> objects;
    MyObjectList& operator<<( const MyObject o )
    { 
        objects.Push_back( o );
        return *this; 
    }
};

あなたはあなたの構造体をパラメータとして取る関数を作成することができます。例えば:

someFunc( MyObjectList &objects );

そして、このようにその関数を呼び出すことができます。

someFunc( MyObjectList() << MyObject(1) <<  MyObject(2) <<  MyObject(3) );

このようにして、動的にサイズ設定されたオブジェクトのコレクションを構築し、1つのクリーンな行で関数に渡すことができます。

4
BuvinJ

これに関連して、ベクトルをクイックステートメントに入れる準備が完全に整った状態にしたい場合(例えば、すぐに別の関数に渡す場合)、以下を使用することができます。

#define VECTOR(first,...) \
   ([](){ \
   static const decltype(first) arr[] = { first,__VA_ARGS__ }; \
   std::vector<decltype(first)> ret(arr, arr + sizeof(arr) / sizeof(*arr)); \
   return ret;})()

関数例

template<typename T>
void test(std::vector<T>& values)
{
    for(T value : values)
        std::cout<<value<<std::endl;
}

使用例

test(VECTOR(1.2f,2,3,4,5,6));

decltypeについては注意が必要ですが、最初の値が明らかにあなたが望むものであることを確認してください。

3
Josh

B. Stroustrupは、C++ 11版のProgの 16.2.10自己参照 464ページに、連鎖操作のいい方法を説明しています。ラング。関数は参照を返します。ここではベクトルに変更します。こうすればv.pb(1).pb(2).pb(3);のように連鎖することができますが、そのような小さな利益のためには多すぎる作業になるかもしれません。

#include <iostream>
#include <vector>

template<typename T>
class chain
{
private:
    std::vector<T> _v;
public:
    chain& pb(T a) {
        _v.Push_back(a);
        return *this;
    };
    std::vector<T> get() { return _v; };
};

using namespace std;

int main(int argc, char const *argv[])
{
    chain<int> v{};

    v.pb(1).pb(2).pb(3);

    for (auto& i : v.get()) {
        cout << i << endl;
    }

    return 0;
}

1
2
3

2
kometen

「STLベクトルを作成して上記のように初期化するにはどうすればよいですか。最小限の入力作業でこれを行うための最良の方法は何ですか?」

組み込み配列を初期化したときにベクトルを初期化する最も簡単な方法は、C++ 11で導入された初期化子リスト を使用することです

// Initializing a vector that holds 2 elements of type int.
Initializing:
std::vector<int> ivec = {10, 20};


// The Push_back function is more of a form of assignment with the exception of course
//that it doesn't obliterate the value of the object it's being called on.
Assigning
ivec.Push_back(30);

assign(ラベル付きステートメント)が実行された後のivecのサイズは3要素です。

2
user2103487