Если класс имеет только одного конструктора с одним параметром, как объявить массив? Я знаю, что вектор рекомендуется в этом случае. Например, если у меня есть класс
class Foo{
public:
Foo(int i) {}
}
Как объявить массив или вектор, который содержит 10 000 объектов Foo?
Для массива вам нужно будет предоставить инициализатор для каждого элемента массива в точке, где вы определяете массив.
Для вектора вы можете предоставить экземпляр для копирования для каждого члена вектора.
например.
std::vector<Foo> thousand_foos(1000, Foo(42));
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 *
при его удалении. См. Пояснения в комментариях ниже.
Единственный способ определить массив класса без конструктора по умолчанию - это сразу инициализировать его - на самом деле это не вариант с 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;
}
Из того, что я могу сказать в 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 объектов без конструктора по умолчанию.
На самом деле, вы можете делать это, пока используете список инициализации, например
Foo foos[4] = { Foo(0),Foo(1),Foo(2),Foo(3) };
, однако с 10000 объектов это абсолютно непрактично. Я даже не уверен, что вы были достаточно сумасшедшими, чтобы попробовать, примет ли компилятор такой большой список инициализации.
Вам нужно создать массив указателей на Foo.
Foo* myArray[10000];
for (int i = 0; i < 10000; ++i)
myArray[i] = new Foo(i);
Когда вы объявляете объект, у которого нет конструктора по умолчанию, вы должны инициализировать его в объявлении.
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 таких элементов, поэтому вы, возможно, захотите переосмыслить, действительно ли класс не должен иметь значение по умолчанию конструктор.
Другим вариантом может быть использование массива 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
, так как вы не сможете передать его функции, которая ожидает последнего.
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);
}
В прямом Си использование int foo[10000] = {1};
инициализирует первый элемент массива на 1
, а остаток массива на ноль. Не происходит ли в C++ автоинициализация неуказанных членов массива, или для этого требуется конструктор по умолчанию?
Если это имеет смысл для вашего класса, вы можете указать значение по умолчанию для параметра конструктора:
class Foo
{
public:
explicit Foo(int i = 0);
}
Теперь у вас есть конструктор по умолчанию. («Конструктор по умолчанию» - это конструктор, который может быть вызван без аргументов: FAQ )
Я также рекомендовал бы сделать ваш конструктор явным, как я сделал выше. Это предотвратит получение вами Foo
из int
, если вы не хотите их запрашивать.