用硬编码元素初始化std :: vector的最简单方法是什么?


610

我可以创建一个数组并像这样初始化它:

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

如何创建一个std::vector并优雅地对其进行初始化?

我知道的最好方法是:

std::vector<int> ints;

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

有没有更好的办法?


1
如果初始化后不打算更改int的大小,请考虑使用tr1数组。
zr。

@zr,您让我感到好奇...如果我需要固定大小,我自己可以不使用普通的旧数组吗?现在看tr1数组...
Agnel Kurian 2010年

2
tr1::array之所以有用,是因为普通数组不提供STL容器的接口
Manuel 2010年

更改标题以使其明确成为C ++ 03问题。这似乎比通过所有新的标准C ++弄清所有问题的答案要容易得多。
TED

Answers:


547

一种方法是使用数组初始化向量

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

7
@Agnel如果不使用staticconst,它将正常工作,但是它们都使它在使用方式上更加明确,并允许编译器进行其他优化。
Yacoby 2010年

68
我没有反对,但是我很受诱惑。主要是因为仅使用初始化数组就可以为您节省几乎什么。但是,这实际上是C ++的错误,而不是您的错误。
TED

2
您能否解释一下为什么在定义vec向量时使用这些参数。
DomX23

13
sizeof(array)是为数不多的例外之一,它允许获取数组元素的总大小,而不是arr指针的大小。所以基本上他使用的是vector(pointer_to_first_element,pointer_to_first_element + size_in_bytes_of_the_whole_array / size_of_one_element),即:vector(pointer_to_first_element,pointer_after_final_element)。该类型已经使用<int>给出,因此向量知道一个元素有多少。请记住,迭代器可以视为指针,因此您基本上是在使用vector(迭代器开始,迭代器结束)构造函数
Johnny Pauling 2012年

11
@TED:有时您需要修改结果向量。例如,您可能需要始终具有一些默认参数,有时还需要为其添加一些自定义参数。
DarkWanderer 2014年

640

如果您的编译器支持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_ofstd::deque在后台构造一个),因此对于性能关键的代码,您最好像Yacoby所说的那样做。


由于向量是自动调整大小的,因此也可以将其初始化为空吗?喜欢在构造函数:this->vect = {};
Azurespot

3
@Azurespot您只需对其进行初始化,它将为空:std::vector<T> vector;
路加福音

2
以防万一有人好奇std::vector<int> v = {1, 2, 3, 4};,vector initializer list constructor会被要求进行这种初始化,其文档可以在本C++ 11节中找到。
simomo

103

如果可以,请使用现代的C ++ [11,14,17,...]方法:

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

在可变长度数组上循环或使用的旧方法sizeof()在眼睛上确实很可怕,就精神上的负担而言完全没有必要。uck


2
公平地说,这原本是C ++ 03问题,但我希望人们/公司采用新标准。C ++仍需要标准库中的可变长度数组(VLA)实现,类似于Eigen和Boost中可用的实现。
亚当·埃里克森

不幸的是,这种方法在某些情况下是有问题的,例如open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467。uck
Lightness Races in Orbit,

如果“同类型对象的集合的列表初始化”是您的事,那么您的代码库中可能存在更大的问题……我认为没有任何应用程序可以证明调试问题的合理性。
亚当·埃里克森

77

在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))

当然,我没有拒绝投票,但是我仍然有一个问题:数组的大小何时不是编译时间常数?即,在哪种情况下,您将在第二个代码段中使用第一个解决方案,而不是第三个代码段?
曼努埃尔

4
@Manuel,数组的大小是类型的一部分,因此,它是一个编译时间常数。现在,选项1使用该编译时间常数'N'作为函数的返回值。函数的返回不是编译时,而是运行时值,即使它可能在调用位置被内联为常量值也是如此。不同之处在于您无法做到:int another[size_of_array(array)],而您却可以做到int another[ARRAY_SIZE(array)]
DavidRodríguez-dribeas 2010年

1
在选项3中:“声明的,未定义的”的意思不是我真正的意思吗?那么变量不会占用额外的内存吗?
To1ne 2011年

1
@ To1ne实际上是函数声明,而不是变量。定义它的原因是,除了sizeof不需要定义的表达式外,我们实际上不需要该函数。尽管您实际上可以提供一个定义,但是要正确地执行定义,则需要静态分配数组并返回对其的引用,接下来的问题是什么是数组的值?(还要注意,这意味着该函数实例化的每个类型/大小组合只有一个数组!)由于对它没有明智的用法,所以我宁愿避免使用它。
大卫·罗德里格斯(DavidRodríguez)-dribeas 2012年

1
@mhd:您不能使用该语言构造一个空数组。'int arr [0] = {};' 不是有效的C ++代码。但是正确的是,如果要初始化一个空向量和一个非空向量,则必须使用不同的构造。由于C ++ 11,这是一个非问题,你可以使用初始化列表构造
dribeas大卫-罗德里格斯

61

在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);

2
C ++ 11还支持std::beginstd::end用于数组,因此向量也可以像一样初始化static const int arr[] = {10,20,30}; vector<int> vec(begin(arr), end(arr));
Jaege

54

只是以为我会扔掉我的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中编译。嘘


1
此技术还可用于使函数重载以接受具有类型大小的数组。
2012年

4
你能解释一下const T (&data)[N]吗?如何在调用中推导出数组的大小makeVector(values)
Patryk 2015年

36

在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};

28

从...开始:

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};

22

对于向量初始化-

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]);
}

除了这些以外,上面还介绍了使用某些代码的各种其他方式。我认为,这些方式很容易记住,而且写起来很快。



16

我使用构建自己的解决方案va_arg。此解决方案符合C ++ 98。

#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;
}

演示版


14

如果您的编译器支持可变参数宏(大多数现代编译器都适用),则可以使用以下宏将向量初始化转换为单行代码:

#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});

这将创建一个名为my_vector的int新向量,其元素为1,2,3,4。


13

如果您不想使用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;
}

1
我还无法弄清楚如何使用此代码,但看起来很有趣。
Daniel Buckmaster 2012年

就像上面的评论之一。只是重载+ =和逗号运算符。为了清楚起见((((v+=1),2),3),4),5) ,请vector<T> += T加上括号:这是它的工作原理:首先,返回一个vector_inserter调用它vi来封装原始向量,然后vi,T将T添加到vi封装并返回自身的原始向量中,以便我们vi,T再次执行。
Piti Ongmongkolkul '04年

我认为这段代码在gcc 4.2.1上无法正常工作,因为返回对+ =运算符内部局部变量的引用,但想法很出色。我编辑了代码,然后出现了另一个副本构造函数。现在的流程是-> + =-> ctor->逗号->复制-> dtor->逗号......->逗号-> dtor。
Yevhen 2012年

我可能会重载<<而不是+ =。至少<<由于位移和cout已经具有模糊的副作用规则
Speed8ump

11

在C ++ 11中:

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

21
如果您已经在使用C ++ 11,则最好直接使用- vector<int> arr = {10, 20, 30};
2015年

实际上,我有一个传入的int [](一些C lib),并且想推送到一个向量中(C ++ lib)。这个答案有所帮助,其余的没有;-)
星云

10

您可以使用boost :: assign做到这一点。

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

这里详细


19
在很长一段时间内,我还没有看到运营商超负荷滥用的更糟情况。是将+=1,2,3,4 .. 附加到值的末尾,还是 1 添加到第一个元素,2添加到第二个元素,3添加到第3个元素(因为这样的语法在MATLAB-像语言一样)
bobobobo

10

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)

7

可以使用以下方法在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};

第三个仅在C ++ 11起才允许。


5

这里有很多很好的答案,但是由于我在阅读本文之前是独立到达我自己的,所以我认为无论如何我都会把我扔在这里...

这是我正在使用的一种方法,它将在编译器和平台之间通用:

创建一个结构或类作为对象集合的容器。为<<定义一个运算符重载函数。

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) );

这样,您可以在一条简单的代码行中生成动态大小的对象集合并将其传递给函数!


4

如果您希望某些东西与Boost :: assign具有相同的一般顺序,而又没有对Boost产生依赖关系,那么以下内容至少大致相似:

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
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>

问题指出C ++ 03(不是11)
Mike P

1
我认为在回答此问题时并没有指定03。虽然记不清了。但是,对于寻求快速解决方案的人来说,它仍然是一个有用的答案。
shaveenk

4
// 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

如果数组是:

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 


3

相关的,如果您想让向量完全准备好进入快速语句(例如,立即传递给另一个函数),则可以使用以下代码:

#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,但要确保第一个值显然是您想要的。


2

“如何创建一个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);

执行分配(标记的语句)后,ivec的大小为3个元素。


在相似的行中,我正在尝试初始化地图std :: map <int,bool> catinfo = {{1,false}}; 但是然后出现此错误错误:在C ++ 98中,“ catinfo”必须由构造函数而不是“ {...}”初始化
pdk

2

B. Stroustrup 在Prog的C ++ 11版本的第464页的16.2.10自引用中描述了一种链接操作的好方法。郎 函数返回引用的地方,此处已修改为向量。这样您就可以像这样串连起来,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


犰狳库这样做是为了矩阵初始化,但是使用<<操作符而不是命名函数:arma.sourceforge.net/docs.html#element_initialisation
Agnel Kurian

2

有多种方法可以对向量进行硬编码,我将分享几种方法:

  1. 通过逐一推送值进行初始化
// Create an empty vector 
    vector<int> vect;  

    vect.push_back(10); 
    vect.push_back(20); 
    vect.push_back(30); 
  1. 初始化类似数组
vector<int> vect{ 10, 20, 30 };
  1. 从数组初始化
    int arr[] = { 10, 20, 30 }; 
    int n = sizeof(arr) / sizeof(arr[0]); 

    vector<int> vect(arr, arr + n); 
  1. 从另一个向量初始化
    vector<int> vect1{ 10, 20, 30 }; 

    vector<int> vect2(vect1.begin(), vect1.end()); 

0

最简单,更符合人体工程学的方式(对于C ++ 11或更高版本):

auto my_ints = {1,2,3};

0

如果您想在自己的课堂上上课:

#include <initializer_list>
Vector<Type>::Vector(std::initializer_list<Type> init_list) : _size(init_list.size()),
_capacity(_size),
_data(new Type[_size])
{
    int idx = 0;
    for (auto it = init_list.begin(); it != init_list.end(); ++it)
        _data[idx++] = *it;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.