Подтвердить что ты не робот

Как объявить массив объектов, у класса которых нет конструктора по умолчанию?

Если класс имеет только один конструктор с одним параметром, как объявить массив? Я знаю, что этот вектор рекомендуется в этом случае. Например, если у меня есть класс

class Foo{

public:
Foo(int i) {}

}

Как объявить массив или вектор, содержащий 10000 объектов Foo?

4b9b3361

Ответ 1

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

Для вектора вы можете предоставить экземпляр для копирования для каждого члена вектора.

например.

std::vector<Foo> thousand_foos(1000, Foo(42));

Ответ 2

Собственно, вы можете сделать это, пока вы используете список инициализации, например

Foo foos[4] = { Foo(0),Foo(1),Foo(2),Foo(3) };

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

Ответ 3

sbi получил лучший ответ для простых массивов, но не привел пример. Так что...

Вы должны использовать новое размещение:

char *place = new char [sizeof(Foo) * 10000];
Foo *fooArray = reinterpret_cast<Foo *>(place);
for (unsigned int i = 0; i < 10000; ++i) {
    new (fooArray + i) Foo(i); // Call non-default constructor
}

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

// In some cleanup code somewhere ...
for (unsigned int i = 0; i < 10000; ++i) {
    fooArray[i].~Foo();
}

// Don't forget to delete the "place"
delete [] reinterpret_cast<char *>(fooArray);

Это единственный раз, когда вы когда-либо видите законный явный вызов деструктора.

ПРИМЕЧАНИЕ. Первая версия этого файла имела тонкую ошибку при удалении "места". Важно вернуть "место" к тому же типу, который был введен в действие. Другими словами, fooArray должен быть отброшен на char * при его удалении. См. Комментарии ниже для объяснения.

Ответ 4

Вам нужно будет сделать массив указателей в Foo.

Foo* myArray[10000];
for (int i = 0; i < 10000; ++i)
    myArray[i] = new Foo(i);

Ответ 5

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

Foo a; // not allowed
Foo b(0); // OK

То же самое относится к массивам таких типов:

Foo c[2]; // not allowed
Foo d[2] = { 0, 1 }; // OK
Foo e[] = { Foo(0), Foo(1), Foo(2) }; // also OK

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

Ответ 6

Вы должны использовать агрегатный инициализатор, с 10000 индивидуальных инициализаторов между {}

Foo array[10000] = { 1, 2, 3, ..., 10000 };

Конечно, указание 10000 инициализаторов - это что-то из области невозможности, но вы сами просили об этом. Вы хотели объявить массив из 10000 объектов без конструктора по умолчанию.

Ответ 7

Единственный способ определить массив класса без конструктора по умолчанию - это сразу же его инициализировать - не вариант с 10000 объектами.

Однако вы можете выделить достаточную необработанную память, какой бы вы ни хотели, и использовать размещение new для создания объектов в этой памяти. Но если вы хотите это сделать, лучше использовать std::vector, который делает именно это:

#include <iostream>
#include <vector>

struct foo {
    foo(int) {}
};

int main()
{
    std::vector<foo> v;
    v.resize(10000,foo(42));
    std::cout << v.size() '\n';
    return 0;
}

Ответ 8

class single
{
    int data;
public:
    single()
    {
        data = 0;
    }
    single(int i)
    {
        data = i;
    }
};

// in main()
single* obj[10000];
for (unsigned int z = 0; z < 10000; z++) 
{
    obj[z] = new single(10);
}

Ответ 9

Другим вариантом может быть использование массива boost::optional<Foo>:

boost::optional<Foo> foos[10]; // No construction takes place
                               // (similar to vector::reserve)

foos[i] = Foo(3); // Actual construction

Одно из предостережений заключается в том, что вам нужно будет получить доступ к элементам с синтаксисом указателя:

bar(*foos[2]); // "bar" is a function taking a "Foo"

std::cout << foos[3]->baz(); // "baz" is a member of "Foo"

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

Другой оговоркой является то, что это не истинная замена массива Foo, так как вы не сможете передать его функции, ожидающей последнего.

Ответ 10

В прямой C, используя int foo[10000] = {1};, будет инициализировать первый элемент массива до 1, а остаток массива - к нулю. Не С++ не автоинициализирует неопределенные члены массива, или для этого требуется конструктор по умолчанию?

Ответ 11

Если это имеет смысл для вашего класса, вы можете указать значение по умолчанию для вашего параметра конструктора:

class Foo
{ 
public: 
  explicit Foo(int i = 0); 
}

Теперь у вас есть конструктор по умолчанию. ( "Конструктор по умолчанию" - это конструктор, который можно вызвать без аргументов: FAQ)

Я также рекомендовал бы сделать ваш конструктор явным, как я сделал выше. Это предотвратит получение Foo из int, если вы не хотите запрашивать их.

Ответ 12

Попробуйте это.

Foo **ppInstances=0;
    size_t total_instances = 10000;

    for(int parent=0;parent < total_instances;parent++){
        ppInstances[parent]=new Foo( parent ); 
        ppInstances++;
    }
    for(int parent=0;parent < total_instances;parent++){
        delete *ppInstances;
        ppInstances--;
    }

код >