Как инициализировать stl-вектор объектов, которые сами имеют нетривиальные конструкторы?
предположим, что у меня есть следующий класс:
class MyInteger {
private:
int n_;
public:
MyInteger(int n) : n_(n) {};
// MORE STUFF
};
И пусть этот класс не имеет тривиального конструктора по умолчанию MyInteger()
. Я должен всегда снабжать int
, чтобы инициализировать его по какой-либо причине. А потом предположим, что где-то в моем коде мне нужен vector<MyInteger>
. Как инициализировать каждый компонент MyInteger
в этом vector<>
?
У меня две ситуации (возможно, одно и то же решение, но я все равно их укажу), нормальная переменная внутри функции:
int main(){
vector<MyInteger> foo(10); //how do I initialize each
//MyInteger field of this vector?
doStuff(foo);
}
и как данные в классе:
class MyFunClass {
private:
vector<MyInteger> myVector;
public:
MyFunClass(int size, int myIntegerValue) : myVector(size) {};
// what do I put here if I need the
// initialization to call MyInteger(myIntegerValue) for all
// components of myVector?
};
Возможно ли это сделать только в списке инициализации или я должен написать инициализацию вручную в конструкторе MyFunClass (int, int)?
Это кажется очень простым, но все же я как-то пропустил его inmy книгу и не могу найти в Интернете.
Ответы
Ответ 1
Есть много способов добраться туда. Вот некоторые из них (в определенном порядке присутствия).
Используйте конструктор vector(size_type n, const T& t)
. Он инициализирует вектор с n
копиями t
. Например:
#include <vector>
struct MyInt
{
int value;
MyInt (int value) : value (value) {}
};
struct MyStuff
{
std::vector<MyInt> values;
MyStuff () : values (10, MyInt (20))
{
}
};
Вставляйте элементы в вектор по одному. Это может быть полезно, когда значения должны быть разными. Например:
#include <vector>
struct MyInt
{
int value;
MyInt (int value) : value (value) {}
};
struct MyStuff
{
std::vector<MyInt> values;
MyStuff () : values ()
{
values.reserve (10); // Reserve memory not to allocate it 10 times...
for (int i = 0; i < 10; ++i)
{
values.push_back (MyInt (i));
}
}
};
Другой вариант - это список инициализации конструктора, если параметр С++ 0x является опцией:
#include <vector>
struct MyInt
{
int value;
MyInt (int value) : value (value) {}
};
struct MyStuff
{
std::vector<MyInt> values;
MyStuff () : values ({ MyInt (1), MyInt (2), MyInt (3) /* ... */})
{
}
};
Конечно, есть возможность предоставить конструктор по умолчанию и/или использовать что-то другое, кроме std::vector
.
Надеюсь, что это поможет.
Ответ 2
Если элементы вектора не являются конструктивными по умолчанию, то есть определенные вещи, которые вы не можете сделать с вектором. Вы не можете написать это (пример 1):
vector<MyInteger> foo(10);
Однако вы можете написать это (пример 2):
vector<MyInteger> foo(10, MyInteger(37));
(Для этого требуется только конструктор копирования.) Второй аргумент - это инициализатор для элементов вектора.
В вашем случае вы также можете написать:
vector<MyInteger> foo(10, 37);
... поскольку MyInteger имеет неявный конструктор, принимающий значение "int" в качестве аргумента. Таким образом, компилятор будет отсылать 37 в MyInteger (37) и дает тот же результат, что и в примере 2.
Возможно, вам захочется изучить документацию на std::vector.
Ответ 3
vector<MyInteger> foo(10, MyInteger(MY_INT_VALUE));
MyFunClass(int size, int myIntegerValue) : myVector(size, MyInteger(myIntegerValue)) {};
Ответ 4
Помимо всех ответов, которые очень хорошо отвечали на вопрос, в случае, если ваш класс MyInteger не является конструктивным для копирования, вы можете использовать этот трюк: вместо создания vector< MyInteger>
вы могли бы создать vector< shared_ptr< MyInteger > >