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

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

class Foo{

public:
Foo(int i) {}

}

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

13
задан Eight 5 June 2012 в 18:50
поделиться

11 ответов

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

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

например.

std::vector<Foo> thousand_foos(1000, Foo(42));
15
ответ дан 1 December 2019 в 17:55
поделиться

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
}

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

// 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 * при его удалении. См. Пояснения в комментариях ниже.

8
ответ дан 1 December 2019 в 17:55
поделиться

Единственный способ определить массив класса без конструктора по умолчанию - это сразу инициализировать его - на самом деле это не вариант с 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;
}
1
ответ дан 1 December 2019 в 17:55
поделиться

Из того, что я могу сказать в Reflector, компонент PowerPack LineShape рисует с помощью объекта Graphics из исходного события Paint контейнера. Изменение свойств данного объекта Graphics может повлиять на все остальное в контейнере, который красится после формы.

В каком образце содержатся объекты LineShape? (Если это пользовательский элемент управления, вы создаете растровое изображение в какой-то момент? Как?) Если они находятся внутри пользовательского элемента управления с низкой глубиной цвета, это может быть источником проблемы. LineShape рисует сглаживание по умолчанию на моем компьютере.

-121--4349358-

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

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

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

-121--2750480-

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

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

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

1
ответ дан 1 December 2019 в 17:55
поделиться

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

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

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

13
ответ дан 1 December 2019 в 17:55
поделиться

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

Foo* myArray[10000];
for (int i = 0; i < 10000; ++i)
    myArray[i] = new Foo(i);
4
ответ дан 1 December 2019 в 17:55
поделиться

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

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

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

2
ответ дан 1 December 2019 в 17:55
поделиться

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

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 , так как вы не сможете передать его функции, которая ожидает последнего.

0
ответ дан 1 December 2019 в 17:55
поделиться
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);
}
1
ответ дан 1 December 2019 в 17:55
поделиться

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

.
0
ответ дан 1 December 2019 в 17:55
поделиться

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

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

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

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

0
ответ дан 1 December 2019 в 17:55
поделиться
Другие вопросы по тегам:

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