像ac数组一样如何初始化'const std :: vector <T>'


79

有没有一种优雅的方法来创建和初始化const std::vector<const T>类似const T a[] = { ... }的固定数目(很少)的值?
我需要经常调用一个期望vector<T>,但是在我的情况下,这些值永远不会改变。

原则上我想到了类似

namespace {
  const std::vector<const T> v(??);
}

因为v不会在此编译单元之外使用。

Answers:


61

您要么必须等待C ++ 0x,要么使用Boost.Assign之类的工具来执行此操作。

例如:

#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope

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

对于C ++ 11:

vector<int> luggage_combo = { 1, 2, 3, 4, 5 };

1
“必须”可能会有点强;两步法也可以。尽管升压方法肯定是好的。
08年

弄乱你的意思是:#include <boost / assign / std / vector.hpp>
Zac 2010年

1
@Jason:boost.assign在vector <T>上定义了operator + =和operator的模板重载
Ferruccio

但是如何截取每个逗号值?
詹森·S

41
12345?我的行李上有相同的组合!
JRG

39

如果您问如何初始化const向量,使其具有有趣的内容,那么答案可能是使用复制构造函数。首先,您费力地填写一个向量,然后从中创建新的const向量。或者,您可以使用vector<InputIterator>(InputIterator, InputIterator)构造函数模板从其他某种容器或数组初始化。如果是数组,则可以使用初始化列表进行定义。

希望这样的事情接近您想要的东西:

const T ra[3] = {t1, t2, t3};
const vector<const T> v(ra, ra+3);

如果您问如何将const向量传递给采用向量的函数,那么答案是:

  • 您不能这样做,因为该函数可能会更改矢量,并且您的对象/引用是const。制作原始文件的非const副本,然后将其传入。

要么

  • 使用const_cast去除常量性,以便将其传递到它接受一个非const载体,但你只是这么碰巧知道会不会修改向量的功能。

后者是其中的一件事情,很正确的做法是,使任何看到它的人对护目镜发表评论,而事实是他们什么也不做。这正是const_cast目的,但是有一个合理的论据说,如果您需要const_cast,您已经迷路了。

做到这两种事情(使用复制构造函数从非常量对象创建一个常量向量,然后丢弃常量)绝对是错误的-您应该只使用了非常量向量。因此,最多选择其中一项来做...

[编辑:只注意到你在谈论之间的差异vector<T>const vector<const T>。不幸的是在STL,vector<const T>并且vector<T>是完全无关的类型,并在它们之间转换的唯一方法是通过复制。向量和数组之间的区别-aT**可以无声且安全地转换为const T *const *]


如果我不想复制t1,t2,t3,该如何做到最好?这是到目前为止我发现的唯一/最佳解决方案:<code> const int * p =&ra [0]; vector <const int *> v; for(int i = 0; i <size; ++ i,++ p)v.push_back(p); </ code>
AudioDroid

@AudioDroid:是的,没有任何方法可以将任何内容复制到向量中(或者在C ++ 11中将其移动),所以最接近的是指针(或智能指针)向量。但是,如果您已经在数组中拥有三个对象,那么通常没有必要创建指向它们的指针向量:只需将数组用于要使用该向量的对象即可。
史蒂夫·杰索普

15

简短而肮脏的方式(类似于Boost的list_of()

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;

template <typename T>
struct vlist_of : public vector<T> {
    vlist_of(const T& t) {
        (*this)(t);
    }
    vlist_of& operator()(const T& t) {
        this->push_back(t);
        return *this;
    }
};

int main() {
    const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5);
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\n"));
}

现在,C ++ 11具有初始化程序列表,因此您不需要那样做,甚至不需要使用Boost。但是,作为示例,您可以像这样在C ++ 11中更有效地执行上述操作:

    #include <iostream>
    #include <vector>
    #include <utility>
    #include <ostream>
    using namespace std;

    template <typename T>
    struct vlist_of : public vector<T> {
        vlist_of(T&& t) {
            (*this)(move(t));
        }
        vlist_of& operator()(T&& t) {
            this->push_back(move(t));
            return *this;
        }
    };

    int main() {
        const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5);
        for (const auto& i: v) {
            cout << i << endl;
        }
    }

但是,它仍然没有使用C ++ 11初始化程序列表有效,因为没有operator=(vlist_of&&)为vector定义。

tjohns20的如下修改方式可能是更好的c ++ 11 vlist_of

#include <iostream>
#include <vector>
#include <utility>
using namespace std;

template <typename T>
class vlist_of {
    public:
        vlist_of(T&& r) {
            (*this)(move(r));
        }
        vlist_of& operator()(T&& r) {
            v.push_back(move(r));
            return *this;
        }
        vector<T>&& operator()() {
            return move(v);
        }
    private:
        vector<T> v;
    
};

int main() {
    const auto v = vlist_of<int>(1)(2)(3)(4)(5)();
    for (const auto& i : v) {
        cout << i << endl;
    }
    
}

邪恶,但对测试等有用。++
Eli Bendersky 2010年

12

就像其他人所说的那样,除非您将向量指针指向源数组,否则不能像初始化C样式数组那样初始化向量。但是在这种情况下,如果向量是全局const,为什么不只使用旧的C样式数组呢?

const int MyInts[] = {
1, 2, 3, 4, 5};

const size_t NumMyInts = sizeof(MyInts)/sizeof(MyInts[0]);

您甚至可以针对此数组使用STL算法,就像针对const向量使用算法一样。

const int* myInt = std::find( &MyInts[0], &MyInts[NumMyInts], 3);

4
很好,但是他将其传递给需要向量的函数。他可能无法修改该功能。
Ferruccio

这需要从外部跟踪向量的大小,这在处理许多向量时很麻烦。否则,此解决方案将是最佳解决方案,因为它仅需要内存中整数的一个副本。
MasterHD '16

6

您可以分两个步骤进行操作:

namespace {
    const T s_actual_array[] = { ... };
    const std::vector<const T> s_blah(s_actual_array,
        s_actual_array + (sizeof(s_actual_array) / sizeof(s_actual_array[0])));
}

也许不如您想像的那样美丽,但实用。


5

怎么样:

int ar[]={1,2,3,4,5,6};
const int TotalItems = sizeof(ar)/sizeof(ar[0]);
std::vector<int> v(ar, ar+TotalItems);

没关系,“ Steve Jessop”已经指出了这种方法。
蛋白石2012年

3

这是个老问题,但今天我遇到了同样的问题,这是我所接受的最可接受的方法:

vector<int> initVector(void)
{
    vector<int> initializer;
    initializer.push_back(10);
    initializer.push_back(13);
    initializer.push_back(3);
    return intializer;
}

int main()
{
    const vector<int> a = initVector();
    return 0;
}

避免过度复制的示例:

vector<int> & initVector(void)
{
    static vector<int> initializer;
    if(initializer.empty())
    {
        initializer.push_back(10);
        initializer.push_back(13);
        initializer.push_back(3);
    }
    return intializer;
}

int main()
{
    const vector<int> & a = initVector();
    return 0;
}

0

如果他们都一样,你可以做

vector<T> vec(num_items, item);

但我认为它们不是-在这种情况下,最简洁的方法可能是:

vector<T> vec(num_items);
vec[0] = 15;
vec[1] = 5;
...

C ++ 0x可以让您完全按照您想的方式使用初始化程序列表,但是不幸的是,这并不是一件好事。


0

基于Shadow2531的响应,我正在使用此类初始化向量,而没有像Shadow的解决方案那样实际上从std :: vector继承

template <typename T>
class vector_init
{
public:
    vector_init(const T& val)
    {
        vec.push_back(val);
    }
    inline vector_init& operator()(T val)
    {
        vec.push_back(val);
        return *this;
    }
    inline std::vector<T> end()
    {
        return vec;
    }
private:
    std::vector<T> vec;
};

用法:

std::vector<int> testVec = vector_init<int>(1)(2)(3)(4)(5).end();

与史蒂夫·杰索普(Steve Jessop)的解决方案相比,它创建了更多的代码,但是如果数组的创建对性能没有要求,我发现这是在一行中初始化数组的好方法


0

不知道我是否理解正确。我理解您的问题是这样的:您想将向量初始化为大量元素。push_back()在向量上使用怎么了?:-)

如果您知道要存储的元素数量(或确保它存储的下一个2的次幂),则可以执行此操作,前提是您拥有一个向量类型为X的指针(仅适用于指针):

std::vector< X* > v;
v.reserve(num_elems);
X* p = v.begin();
for (int count = 0; count < num_elems; count++)
   p[count] = some_source[count];

请注意,即使使用,也要添加2个元素的下一个幂push_back()。指向的指针v.begin()将无效。


这段代码有很多问题。您不能只调用vector :: reserve()然后开始操纵指针,并取决于魔术实现的细节,例如2的幂。迭代器转换为指针?那么vector :: size()呢?它甚至在什么编译器和STL库上编译?
08年

我同意这是非常糟糕的代码。一个最好的选择,您应该忘记使用指针/迭代器以及回
退到

不,那是完全合法的C ++代码。STL保证这将起作用:向量将为至少2 ^ n个元素分配连续空间。在所有2 ^ n个元素之后,允许vector重新分配,从而在vector :: begin()后面提供了一个新的空间。抱歉,它可能很hack,但这是标准。:-)
mstrobl

1
...但是,我非常不敢相信使用连续内存保证通过指针添加新值是标准的-对于初学者来说,向量没有机会更新其自身大小,因此我很确定结果此代码的要么未定义,或尺寸为0的矢量
史蒂夫杰索普

1
当然,您可以利用向量中的连续空间。该标准保证了这一点。但是,调用reserve()不足以做到这一点;您必须添加元素以使size()正确。您可以更改代码,以便分配正确数量的元素..
Janm
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.