C++: инициализатор конструктора для массивов

У меня есть мозговая судорога..., как я инициализирую массив объектов правильно в 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 ключевое слово + гибкость с конструкторами.)

64
задан Jason S 9 March 2010 в 15:12
поделиться

8 ответов

Нет пути. Вам нужен конструктор по умолчанию для членов массива, и он будет вызван, после чего вы можете выполнить любую инициализацию, которую хотите, в конструкторе.

52
ответ дан 24 November 2019 в 15:53
поделиться

Не существует синтаксиса построения массива, который можно было бы использовать в этом контексте, по крайней мере, не напрямую. Вы можете выполнить то, что пытаетесь достичь, с помощью чего-то вроде:

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 конструктор по умолчанию.

0
ответ дан 24 November 2019 в 15:53
поделиться

Кажется, это работает, но я не уверен, что это правильно:

#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 тривиально.

2
ответ дан 24 November 2019 в 15:53
поделиться

К сожалению, нет возможности инициализировать элементы массива до 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 };
7
ответ дан 24 November 2019 в 15:53
поделиться

Прямо сейчас вы не можете использовать список инициализаторов для членов массива. Вы застряли, делая это трудным путем.

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}) {}
};
16
ответ дан 24 November 2019 в 15:53
поделиться

При создании объектов в массиве может вызываться только конструктор по умолчанию.

1
ответ дан 24 November 2019 в 15:53
поделиться

Ideas from a twisted mind :

class mytwistedclass{
static std::vector<int> initVector;
mytwistedclass()
{
    //initialise with initVector[0] and then delete it :-)
}

};

теперь установите этот initVector в то значение, которое вы хотите, перед инстанцированием объекта. Затем ваши объекты инициализируются с вашими параметрами.

0
ответ дан 24 November 2019 в 15:53
поделиться

В конкретном случае, когда массив является членом данных класса, вы не можете инициализировать его в текущей версии язык. Для этого нет синтаксиса. Либо предоставьте конструктор по умолчанию для элементов массива, либо используйте std :: vector .

Автономный массив можно инициализировать с помощью агрегатного инициализатора

Foo foo[3] = { 4, 5, 6 };

, но, к сожалению, нет соответствующего синтаксиса для списка инициализаторов конструктора.

1
ответ дан 24 November 2019 в 15:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: