1

I want an array of class objects with unique_ptr:

std::unique_ptr<MyClass[]> arr(new MyClass[n]);

MyClass has no default constructor (and in my case is not supposed to have), so I have to put it explicitly here. I cannot find out how to do it so it is syntactically correct. What is the correct way to write a unique_ptr array of class objects with explicit initialisation?

Clarification

I have a non-default constuctor for MyClass, like this:

MyClass instance(arguments);

Apart from member initialisations, there are also some calculations in the constructor. I want to create a unique_ptr array of MyClass instances and call the constructor for each of the instances. I cannot do that later since MyClass has no default constructor. Can I put (arguments) somewhere in std::unique_ptr<MyClass[]> arr(new MyClass[n])?

Kaiyakha
  • 1,463
  • 1
  • 6
  • 19
  • 1
    Does this answer your question? [Proper way to create unique\_ptr that holds an allocated array](https://stackoverflow.com/questions/21377360/proper-way-to-create-unique-ptr-that-holds-an-allocated-array) – Pepijn Kramer May 08 '22 at 08:13
  • @PepijnKramer It is about an array with explicit initialisation of an instance of a class, not just a plain allocated array – Kaiyakha May 08 '22 at 08:15
  • You will have to either use pointers in such an array, or allocate required space by manipulating bytes (`char`) and then assign initialized values. However before you do that, why don't you just use `std::vector`? – The Dreams Wind May 08 '22 at 08:25
  • @RichardCritten where do I put arguments for the constructor? – Kaiyakha May 08 '22 at 08:26
  • You could also simply derive from `std::array` and provide a constructor. Then use a `unique_ptr` to that class. – Sebastian May 08 '22 at 08:43

1 Answers1

2

The answer below is based on a previous version of the question, in which the array size appeared to be a compile-time constant. If the size of the created array is not a compile-time constant, then it is impossible to pass arguments to the constructors of the elements. In that case std::vector is probably a better choice than array-std::unique_ptr.


It works the same as always for arrays, using aggregate initialization:

std::unique_ptr<MyClass[]> arr(new MyClass[]{
    {...},
    {...},
    {...},
    {...},
    {...}});

where ... are replaced by the argument lists for the constructors of the five elements.

Or if you cannot use list-initialization for the elements, e.g. because that would unintentionally use a std::initializer_list constructor:

std::unique_ptr<MyClass[]> arr(new MyClass[]{
    MyClass(...),
    MyClass(...),
    MyClass(...),
    MyClass(...),
    MyClass(...)});

std::make_unique would usually be preferred for creating std::unique_ptrs, but there is at the moment no overload which allows passing arguments to the constructors of the individual array elements.


If you want to pass the same argument list to each element, a simple solution given that the type is copy-constructible would be to declare one instance and then copy-construct the elements from this instance:

MyClass instance(arguments);
std::unique_ptr<MyClass[]> arr(new MyClass[]{instance, instance, instance, instance, instance);

Otherwise you could write a template function that expands these repeated items for you. (Might add example later.)

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Can I call my constructor here somehow? If creating a single instance, it looks like `MyClass instance(arguments)`. Apart from initialising members, the constructor also has some calculations under the hood, which should also be done – Kaiyakha May 08 '22 at 08:29
  • @Kaiyakha Yes, you replace `...` with `arguments`. If you must use paranthesized initialization instead of list-initialization with braces, you can replace `{...}` with `MyClass(arguments)` as well. – user17732522 May 08 '22 at 08:31
  • Is there any way to have one `(arguments)` for all elements of the array? – Kaiyakha May 08 '22 at 08:36
  • the amount of instances is not known at compile time, sorry for not mentioning that – Kaiyakha May 08 '22 at 08:44
  • 1
    @Kaiyakha Then what you are trying to do is impossible. Use `std::vector` instead. – user17732522 May 08 '22 at 08:45
  • I think it would work with a `std::unique_ptr` with the customDeleter calling `delete[]` – Sebastian May 08 '22 at 11:29
  • @Sebastian That doesn't solve the problem that you can't initialize a `new`ed array's elements with constructor arguments if the size of the array is unknown at compile time. You would need to placement-new each element individually, which then would require a destructor that properly destructs each element. At this point it would get complicated enough that I wouldn't try to avoid `std::vector` without a very good reason. – user17732522 May 08 '22 at 11:33
  • @user17732522 I agree that it would get complicated, and I also would use `std::vector` in 99.9% of those cases anyway instead of a C array. Especially because we do not need a `unique_ptr` with `vector` (the functionality is built in), so we do not even save an indirection. The `vector` can be constructed with exactly the intended size. – Sebastian May 08 '22 at 11:41