如何使用size参数初始化std :: vector并使每个对象独立构造?

时间:2011-01-21 18:56:45

标签: c++

我喜欢创建具有给定大小和值的向量,例如:

std::vector<std::string> names(10);

然而,这几次导致了意想不到的结果。例如,在以下代码中,每个UniqueNumber都具有相同的值:

#include <iostream>
#include <string>
#include <vector>


struct UniqueNumber
{
    UniqueNumber() : mValue(sInstanceCount++)
    {
    }

    inline unsigned int value() const
    {
        return mValue;
    }

private:
    static unsigned int sInstanceCount;
    unsigned int mValue;
};


int UniqueNumber::sInstanceCount(0);


int main()
{
    std::vector<UniqueNumber> numbers(10);
    for (size_t i = 0; i < numbers.size(); ++i)
    {
        std::cout << numbers[i].value() << " ";
    }
}

控制台输出:

0 0 0 0 0 0 0 0 0 0

在查看std :: vector的构造函数时确实有意义:

explicit vector(size_type __n,
                const value_type& __value = value_type(),
                const allocator_type& __a = allocator_type());

显然,矢量是用同一个物体的副本初始化的。

是否还有一种方法可以构建每个对象的默认值?

4 个答案:

答案 0 :(得分:4)

Vector是复制构造元素以进行初始化。

试试:

#include <iostream>
#include <string>
#include <vector>


struct UniqueNumber
{
    UniqueNumber(bool automatic = true) 
        : mValue(automatic?sInstanceCount++:Special)
    { }

    UniqueNumber(UniqueNumber const& other) 
        : mValue(other.mValue==Special?sInstanceCount++:other.mValue)
    { }

    unsigned int value() const
    {
        return mValue;
    }

private:
    static int sInstanceCount;
    unsigned int mValue;
    static unsigned int const Special = ~0U;
};


int UniqueNumber::sInstanceCount(0);


int main()
{
    std::vector<UniqueNumber> numbers(10,UniqueNumber(false));
    for (size_t i = 0; i < numbers.size(); ++i)
    {
        std::cout << numbers[i].value() << " ";
    }
}

答案 1 :(得分:4)

有两种方法可以做到这一点。

漂亮的C ++ 0x方式是利用初始化列表:

std::vector<UniqueNumber> vec = { UniqueNumber(0), UniqueNumber(1) };

显然,这里的问题是你必须完整地指出它们。

在C ++ 03中,我只想使用循环:

std::vector<UniqueNumber> vec;
vec.reserve(10);
for (size_t i = 0; i != 10; ++i) { vec.push_back(UniqueNumber(i)); }

当然,这可以完美地嵌入到构建器函数中:

template <typename ValueType, typename Generator>
std::vector<ValueType> generateVector(size_t size, Generator generator)
{
  std::vector<ValueType> vec;
  vec.reserve(size);
  for (size_t i = 0; i != size; ++i) { vec.push_back(generator()); }
  return vec;
}

随着NRVO的推进,它大致相同,它允许您指定自由创建的值。

使用generate_n中的STL <algorithm>可以实现同样的效果,并且我将包含对lambda语法的感觉。

std::vector<ValueType> vec;
size_t count = 0;
std::generate_n(std::back_inserter(vec), 10, [&]() { return Foo(++count); });

@Eugen在评论中提出的建议:)


注意:如果您希望拥有唯一元素,那么wrt会“惊喜”,或许vector不是最合适的数据结构。如果你真的需要一个vector,我会考虑包装成一个类,以确保元素是唯一的不变量。

答案 2 :(得分:4)

generategenerate_n是专为您想要做的事而设计的。这是一个完整的例子:

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

class Foo
{
public:
    Foo() : n_(++water_) {};
    operator unsigned () const { return n_; }
private:
    static unsigned water_;
    unsigned n_;
};

Foo make_foo()
{
    return Foo();
}

unsigned Foo::water_ = 0;

int main()
{
    vector<Foo> v_foo;
    generate_n(back_inserter(v_foo), 10, &make_foo);
    copy(v_foo.begin(), v_foo.end(), ostream_iterator<unsigned>(cout, " "));
}

输出:1 2 3 4 5 6 7 8 9 10

答案 3 :(得分:3)

您需要添加复制构造函数:

UniqueNumber(const UniqueNumber& un) : mValue(sInstanceCount++)
{ }

std::vector的填充构造函数未调用默认构造函数。相反,它调用默认存在的 copy 构造函数。那个构造函数当然不会增加你的内部静态计数器变量。

您还需要定义赋值运算符。

但是,使用具有std::vector的内部静态计数器的对象将产生意外结果,因为该向量可以在内部复制构造/分配您认为合适的对象。因此,这可能会干扰您在此处所需的复制语义。