Правильный синтаксис для определения массива unique_ptr объектов класса с конструктором

Мне нужен массив объектов класса с 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])?

Отвечает ли это на ваш вопрос? Правильный способ создания unique_ptr, который содержит выделенный массив

Pepijn Kramer 08.05.2022 10:13

@PepijnKramer Речь идет о массиве с явной инициализацией экземпляра класса, а не просто о выделенном массиве.

Kaiyakha 08.05.2022 10:15

Вам придется либо использовать указатели в таком массиве, либо выделять необходимое пространство, манипулируя байтами (char), а затем присваивать инициализированные значения. Однако, прежде чем вы это сделаете, почему бы вам просто не использовать std::vector?

The Dreams Wind 08.05.2022 10:25

@RichardCritten, где мне указать аргументы для конструктора?

Kaiyakha 08.05.2022 10:26

Вы также можете просто получить от std::array<MyClass, N> и предоставить конструктор. Затем используйте unique_ptr для этого класса.

Sebastian 08.05.2022 10:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
42
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ответ ниже основан на предыдущей версии вопроса, в которой размер массива оказался константой времени компиляции. Если размер созданного массива не является константой времени компиляции, то невозможно передать аргументы конструкторам элементов. В этом случае 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 08.05.2022 10:29

@Kaiyakha Да, вы замените ... на arguments. Если вы должны использовать инициализацию в скобках вместо инициализации списком с фигурными скобками, вы также можете заменить {...} на MyClass(arguments).

user17732522 08.05.2022 10:31

Есть ли способ иметь один (arguments) для всех элементов массива?

Kaiyakha 08.05.2022 10:36

количество экземпляров неизвестно во время компиляции, извините, что не упомянул об этом

Kaiyakha 08.05.2022 10:44

@Kaiyakha Тогда то, что вы пытаетесь сделать, невозможно. Вместо этого используйте std::vector.

user17732522 08.05.2022 10:45

Я думаю, что это сработает с std::unique_ptr<MyClass, customDeleter> с вызовом customDeleter delete[]

Sebastian 08.05.2022 13:29

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

user17732522 08.05.2022 13:33

@user17732522 user17732522 Я согласен, что это будет сложно, и я бы все равно использовал std::vector в 99,9% этих случаев вместо массива C. Тем более, что нам не нужен unique_ptr с vector (функционал встроен), поэтому мы даже не сохраняем косвенность. vector может быть построен точно с заданным размером.

Sebastian 08.05.2022 13:41

Другие вопросы по теме