Мне нужен массив объектов класса с unique_ptr:
std::unique_ptr<MyClass[]> arr(new MyClass[n]);
MyClass не имеет конструктора по умолчанию (и в моем случае не должен иметь), поэтому я должен указать его здесь явно. Я не могу понять, как это сделать, так что это синтаксически правильно. Как правильно написать массив unique_ptr объектов класса с явной инициализацией?
Уточнение
У меня есть конструктор не по умолчанию для MyClass, например:
MyClass instance(arguments);
Помимо инициализации членов, в конструкторе также есть некоторые вычисления. Я хочу создать массив unique_ptr из MyClass экземпляров и вызвать конструктор для каждого из них. Я не могу сделать это позже, так как у MyClass нет конструктора по умолчанию. Могу ли я поставить (arguments) где-нибудь в std::unique_ptr<MyClass[]> arr(new MyClass[n])?
@PepijnKramer Речь идет о массиве с явной инициализацией экземпляра класса, а не просто о выделенном массиве.
Вам придется либо использовать указатели в таком массиве, либо выделять необходимое пространство, манипулируя байтами (char), а затем присваивать инициализированные значения. Однако, прежде чем вы это сделаете, почему бы вам просто не использовать std::vector?
@RichardCritten, где мне указать аргументы для конструктора?
Вы также можете просто получить от std::array<MyClass, N> и предоставить конструктор. Затем используйте unique_ptr для этого класса.





Ответ ниже основан на предыдущей версии вопроса, в которой размер массива оказался константой времени компиляции. Если размер созданного массива не является константой времени компиляции, то невозможно передать аргументы конструкторам элементов. В этом случае std::vector, вероятно, лучший выбор, чем array-std::unique_ptr.
Он работает так же, как и всегда для массивов, используя агрегатную инициализацию:
std::unique_ptr<MyClass[]> arr(new MyClass[]{
{...},
{...},
{...},
{...},
{...}});
где ... заменены списками аргументов для конструкторов из пяти элементов.
Или, если вы не можете использовать инициализацию списка для элементов, например. потому что это непреднамеренно использовало бы конструктор std::initializer_list:
std::unique_ptr<MyClass[]> arr(new MyClass[]{
MyClass(...),
MyClass(...),
MyClass(...),
MyClass(...),
MyClass(...)});
std::make_unique обычно предпочтительнее для создания std::unique_ptr, но на данный момент нет перегрузки, позволяющей передавать аргументы конструкторам отдельных элементов массива.
Если вы хотите передать один и тот же список аргументов каждому элементу, простым решением, учитывая, что тип можно скопировать, будет объявление одного экземпляра, а затем копирование и создание элементов из этого экземпляра:
MyClass instance(arguments);
std::unique_ptr<MyClass[]> arr(new MyClass[]{instance, instance, instance, instance, instance);
В противном случае вы могли бы написать шаблонную функцию, которая расширяет для вас эти повторяющиеся элементы. (Может быть, добавить пример позже.)
Могу ли я как-то вызвать здесь свой конструктор? При создании одного экземпляра это выглядит как MyClass instance(arguments). Помимо инициализации элементов, конструктор также имеет некоторые вычисления под капотом, которые также должны быть выполнены.
@Kaiyakha Да, вы замените ... на arguments. Если вы должны использовать инициализацию в скобках вместо инициализации списком с фигурными скобками, вы также можете заменить {...} на MyClass(arguments).
Есть ли способ иметь один (arguments) для всех элементов массива?
количество экземпляров неизвестно во время компиляции, извините, что не упомянул об этом
@Kaiyakha Тогда то, что вы пытаетесь сделать, невозможно. Вместо этого используйте std::vector.
Я думаю, что это сработает с std::unique_ptr<MyClass, customDeleter> с вызовом customDeleter delete[]
@Sebastian Это не решает проблему, заключающуюся в том, что вы не можете инициализировать элементы массива newed с аргументами конструктора, если размер массива неизвестен во время компиляции. Вам нужно будет размещать каждый элемент отдельно, что затем потребует деструктора, который правильно уничтожает каждый элемент. В этот момент это стало бы достаточно сложным, чтобы я не пытался избежать std::vector без очень веской причины.
@user17732522 user17732522 Я согласен, что это будет сложно, и я бы все равно использовал std::vector в 99,9% этих случаев вместо массива C. Тем более, что нам не нужен unique_ptr с vector (функционал встроен), поэтому мы даже не сохраняем косвенность. vector может быть построен точно с заданным размером.
Отвечает ли это на ваш вопрос? Правильный способ создания unique_ptr, который содержит выделенный массив