У меня есть мозговая судорога..., как я инициализирую массив объектов правильно в C++?
пример немассива:
struct Foo { Foo(int x) { /* ... */ } };
struct Bar {
Foo foo;
Bar() : foo(4) {}
};
пример массива:
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
// ??? I know the following syntax is wrong, but what's correct?
Baz() : foo[0](4), foo[1](5), foo[2](6) {}
};
править: Дикие и сумасшедшие идеи обходного решения ценятся, но они не помогут мне в моем случае. Я работаю над встроенным процессором где станд.:: вектор и другие конструкции STL не доступны, и очевидное обходное решение должно сделать конструктора по умолчанию и иметь явное init()
метод, который можно назвать после времени создания, так, чтобы я не использовал инициализаторы вообще. (Это - один из тех случаев, где я стал испорченным Java final
ключевое слово + гибкость с конструкторами.)
Нет пути. Вам нужен конструктор по умолчанию для членов массива, и он будет вызван, после чего вы можете выполнить любую инициализацию, которую хотите, в конструкторе.
Не существует синтаксиса построения массива, который можно было бы использовать в этом контексте, по крайней мере, не напрямую. Вы можете выполнить то, что пытаетесь достичь, с помощью чего-то вроде:
Bar::Bar()
{
static const int inits [] = {4,5,6};
static const size_t numInits = sizeof(inits)/sizeof(inits[0]);
std::copy(&inits[0],&inits[numInits],foo); // be careful that there are enough slots in foo
}
... но вам нужно предоставить Foo конструктор по умолчанию.
Кажется, это работает, но я не уверен, что это правильно:
#include <iostream>
struct Foo { int x; Foo(int x): x(x) { } };
struct Baz {
Foo foo[3];
static int bar[3];
// Hmm...
Baz() : foo(bar) {}
};
int Baz::bar[3] = {4, 5, 6};
int main() {
Baz z;
std::cout << z.foo[1].x << "\n";
}
Вывод:
$ make arrayinit -B CXXFLAGS=-pedantic && ./arrayinit
g++ -pedantic arrayinit.cpp -o arrayinit
5
Caveat emptor.
Edit: нет, Комо отвергает это.
Еще одно изменение: это своего рода обман, он просто перемещает инициализацию массива по элементам в другое место. Поэтому для Foo по-прежнему требуется конструктор по умолчанию, но если у вас нет std :: vector
, вы можете реализовать для себя абсолютный минимум, который вам нужен:
#include <iostream>
struct Foo {
int x;
Foo(int x): x(x) { };
Foo(){}
};
// very stripped-down replacement for vector
struct Three {
Foo data[3];
Three(int d0, int d1, int d2) {
data[0] = d0;
data[1] = d1;
data[2] = d2;
}
Foo &operator[](int idx) { return data[idx]; }
const Foo &operator[](int idx) const { return data[idx]; }
};
struct Baz {
Three foo;
static Three bar;
// construct foo using the copy ctor of Three with bar as parameter.
Baz() : foo(bar) {}
// or get rid of "bar" entirely and do this
Baz(bool) : foo(4,5,6) {}
};
Three Baz::bar(4,5,6);
int main() {
Baz z;
std::cout << z.foo[1].x << "\n";
}
z.foo
на самом деле не является массивом, но выглядит примерно так же, как и вектор. Добавление функций begin ()
и end ()
в Three тривиально.
К сожалению, нет возможности инициализировать элементы массива до C ++ 0x.
Вы можете использовать std :: vector и push_back экземпляры Foo в теле конструктора.
Вы можете дать Foo конструктор по умолчанию (может быть закрытым и сделать Baz другом).
Вы можете использовать объект массива, который является копируемым (boost или std :: tr1) и инициализируется из статического массива:
#include <boost/array.hpp>
struct Baz {
boost::array<Foo, 3> foo;
static boost::array<Foo, 3> initFoo;
Baz() : foo(initFoo)
{
}
};
boost::array<Foo, 3> Baz::initFoo = { 4, 5, 6 };
Прямо сейчас вы не можете использовать список инициализаторов для членов массива. Вы застряли, делая это трудным путем.
class Baz {
Foo foo[3];
Baz() {
foo[0] = Foo(4);
foo[1] = Foo(5);
foo[2] = Foo(6);
}
};
В C++0x можно записать:
class Baz {
Foo foo[3];
Baz() : foo({4, 5, 6}) {}
};
При создании объектов в массиве может вызываться только конструктор по умолчанию.
Ideas from a twisted mind :
class mytwistedclass{
static std::vector<int> initVector;
mytwistedclass()
{
//initialise with initVector[0] and then delete it :-)
}
};
теперь установите этот initVector
в то значение, которое вы хотите, перед инстанцированием объекта. Затем ваши объекты инициализируются с вашими параметрами.
В конкретном случае, когда массив является членом данных класса, вы не можете инициализировать его в текущей версии язык. Для этого нет синтаксиса. Либо предоставьте конструктор по умолчанию для элементов массива, либо используйте std :: vector
.
Автономный массив можно инициализировать с помощью агрегатного инициализатора
Foo foo[3] = { 4, 5, 6 };
, но, к сожалению, нет соответствующего синтаксиса для списка инициализаторов конструктора.