79

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

原则上我想到了类似的东西

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

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

4

10 回答 10

61

对于 C++11:

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

原答案:

您要么必须等待 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;
于 2008-10-23T20:56:10.093 回答
39

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

希望这样的事情接近你想要的:

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

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

  • 你不能,因为函数可能会改变向量并且你的对象/引用是常量。制作原始副本的非常量副本,然后将其传入。

或者

  • 用于const_cast删除常量,以便将其传递给一个函数,该函数采用非常量向量,但您恰好知道它不会修改向量。

后者是其中一件非常正确的事情,它会导致任何看到它的人对护目镜发表评论,以及他们什么都不做的事实。这正是它的const_cast用途,但有一个相当有力的论据说,如果你需要const_cast,你已经输了。

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

[编辑:刚刚注意到你在谈论和之间的vector<T>区别const vector<const T>。不幸的是,在 STL 中,vector<const T>它们vector<T>是完全不相关的类型,在它们之间进行转换的唯一方法是通过复制。这是向量和数组之间的区别 - aT**可以静默安全地转换为const T *const *]

于 2008-10-23T21:04:17.457 回答
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&&)为向量定义。

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;
    }
    
}
于 2008-10-31T16:38:34.593 回答
12

正如其他人所说,您不能像初始化 C 样式数组一样初始化向量,除非您给它指向源数组的指针。但是在这种情况下,如果你的向量是一个全局常量,为什么不直接使用一个旧的 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);
于 2008-10-23T21:06:45.563 回答
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])));
}

也许没有你想的那么漂亮,但很实用。

于 2008-10-23T21:25:21.457 回答
5

怎么样:

int ar[]={1,2,3,4,5,6};
const int TotalItems = sizeof(ar)/sizeof(ar[0]);
std::vector<int> v(ar, ar+TotalItems);
于 2012-05-04T09:40:38.020 回答
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;
}
于 2014-01-14T21:55:27.777 回答
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()将无效。

于 2008-10-23T21:10:42.327 回答
0

如果它们都一样,你可以这样做

vector<T> vec(num_items, item);

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

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

C++0x 将让您完全按照您的想法使用初始化列表,但不幸的是,目前这并不是很好。

于 2008-10-23T21:35:50.187 回答
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 的解决方案相比,它创建了更多代码,但如果数组创建不是性能关键,我发现它是在一行中初始化数组的好方法

于 2011-05-09T16:45:13.803 回答