我喜欢创建具有给定大小和值的向量,例如:
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());
显然,向量是用同一对象的副本初始化的。
是否还有一种方法可以构建每个对象的默认值?
generate
要么 generate_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
generate
要么 generate_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
矢量是复制构造初始化的元素。
试试看:
#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() << " ";
}
}
有两种方法可以做到这一点。
好的和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的推进,它大致相同,它允许您指定自由创建的值。
使用STL也可以实现同样的目的 generate_n
在 <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
,我会考虑包装成一个类,以确保元素是唯一的不变量。
您需要添加一个复制构造函数:
UniqueNumber(const UniqueNumber& un) : mValue(sInstanceCount++)
{ }
填充构造函数 std::vector
没有调用默认构造函数。相反,它调用默认值 复制 隐式存在的构造函数。那个构造函数当然不会增加你的内部静态计数器变量。
您还需要定义赋值运算符。
但是,使用具有内部静态计数器的对象 std::vector
会产生意想不到的结果,因为矢量可以在内部复制 - 构造/分配你认为合适的对象。因此,这可能会干扰您在此处所需的复制语义。