0

Is there a way to initialize an array of objects which don't have a default constructor?

struct IndexAndSign {
    const int depth;
    const bool baseIsPositive;

    IndexAndSign(int depth, bool baseIsPositive)
      : depth(depth)
      , baseIsPositive(baseIsPositive) {}
};

void test() {
    auto arr = new IndexAndSign[size]; // error
}
11
  • OT: Please don't use new[] to create your array. If you know the size at compile-time and it will not change at run-time, use std::array, otherwise use std::vector. Commented Aug 1, 2023 at 17:39
  • 1
    No, but you can create an empty std::vector<IndexAndSign>, and then add constructed elements later. Commented Aug 1, 2023 at 17:40
  • how do you want to initialize them? Not via the default constructor, ok, but how else? Commented Aug 1, 2023 at 18:12
  • 1
    Well I wanna initialize them in a loop which iterates over the array -- As soon as you delcared the array (or instantiated using new[]), the initialization is done. You can't go back and "undo" or "redo" the initialization. Better to do what @BoP mentioned -- declare a vector, and add elements to an empty vector. Commented Aug 1, 2023 at 19:06
  • 1
    where are the parameters to the constructor come from when you use the loop? At some point they have to be known, and when they are know at the time you create the array then eg allSignChangeEdges = new IndexAndSign[2]{{1,false},{2,true}}; just works. So the question remains, how do you want to initialize them? Commented Aug 1, 2023 at 21:01

2 Answers 2

0

Basically you can't. As you've figured out, when you use

IndexAndSign* arr = new IndexAndSign[size];

C++ searches for the default (naked) constructor to allocate the correct amount of memory for your objects. But you can't provide naked constructor because of the initializer list due to the const members.

However, there are some loopholes:

  1. The default newbie-hiting aswer is "use std::vector" eg.:
std::vector<IndexAndSign> arr;
for(int i=size; i-->0;){
   int d=0; bool biP=true;              // or something
   arr.push_back(IndexAndSign(d, bIP));
}

However, there is a hidden problem with this solution: it uses the move constructor of your class. And if your class is a little complicated, the default move constructor provided by the compiler will be wrong (according to the rule of n).

  1. You can give a try to the pointer to pointer concept:
IndexAndSign** arr = new IndexAndSign*[size];
for(int i=size; i-->0;){
     int d=0; bool biP=true;              // or something
     arr[i] = new IndexAndSign(d, bIP);
}

The backward of this solution, that if you want to access a member of your object, you have to use -> instead of . eg.:

std::cout << arr[0]->depth << std::endl;

Further reading is here

Sign up to request clarification or add additional context in comments.

Comments

0

Yes, it is doable if you are using c++17 or greater. You do this using std::allocator::allocate to allocate an array and start the lifetime of the array but not the array's objects. The array's objects are then initialized with a placement new in a for loop per OP's comment.

#include <memory>
#include <iostream>

class IndexAndSign {
public:
    const int depth;
    const bool baseIsPositive;
    IndexAndSign(int depth, bool baseIsPositive) : depth(depth), baseIsPositive(baseIsPositive) {}
};

void test() {
    size_t size = 10;
    IndexAndSign* allSignChangeEdges;
    std::allocator<IndexAndSign> my_alloc;
    allSignChangeEdges = my_alloc.allocate(size);

    // demonstrate intitialization in a for loop
    for (size_t i = 0; i < size; i++)
        new(allSignChangeEdges + i) IndexAndSign(static_cast<int>(i), true);

    // show allSignChangeEdges[4].depth == 4
    std::cout << allSignChangeEdges[4].depth << '\n';

    // do stuff and cleanup 
    my_alloc.deallocate(allSignChangeEdges, size);
}

int main()
{
    test();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.