'How to initiate multiple structs

I'm fairly new to C++.

Have a struct Bbox with a constructor with two arguments x and y which I have just added. Before when the constructor had no arguments I could initiate multiple instances of Bbox by doing this and num_components was the number of instances I wanted to create:

Bbox list [num_components];

But how can I do that now when the constructor require arguments?

struct Bbox {
    int
        left,
        top,
        right   = 0,
        bottom  = 0,
        mat_width,
        mat_height;
    
    Bbox(int x, int y):
        left(std::numeric_limits<int>::max()),
        top(std::numeric_limits<int>::max()),
        mat_width(x),
        mat_height(y)
    {}
};

The arguments to initiate the list of Bbox are always the same. Lets say x=10 and y=20 but don't want to add default values to the construtor because the values can vary

c++


Solution 1:[1]

And, to build on @anoop's (excellent) answer, if you use std::vector instead of a C-style array (and you should!), then you can do this:

std::vector <Box> make_boxes (int num_boxes)
{
    return std::vector <Box> (num_boxes);
}

And you would call it thus:

auto my_boxes = make_boxes (10);

But make_boxes is so trivial that it's hardly worth factoring it out, really.


If you want make_boxes to construct boxes with a size specified by the caller, then this would do the job:

std::vector <Box> make_boxes (int num_boxes, int x, int y)
{
    std::vector <Box> boxes;
    boxes.reserve (num_boxes);

    for (int i = 0; i < num_boxes; ++i)
        boxes.emplace_back (x, y);

    return boxes;
}

and then:

auto boxes = make_boxes (10, 10, 20);

Solution 2:[2]

The arguments to initiate the list of Bbox are always the same. Lets say x=10 and y=20

You can add a default constructor that will delegate the work to the parameterized constructor by passing the argument 10 and 20 as shown below:

struct Bbox{
//other parameterized constructor as before

//----------vvvvvvvvvvv------>delegate the work to parameterized ctor
    Bbox(): Bbox(10, 20) //this is a default ctor delegating the work to the other ctor
    {
    }
};

Bbox list[num_components]; //works now assuming num_components is a constant expression

Demo

Solution 3:[3]

Use curly-brackets to initialize the array:

Bbox list [num_components] = {
    // ...
};

Then for each Bbox object you need curly-braces again:

{ SOME_X, SOME_Y }

Combined it would be like:

Bbox list [num_components] = {
    { SOME_X, SOME_Y },
    // ...
    { SOME_OTHER_X, SOME_OTHER_Y }
};

If you want to be able to create default-constructed Bbox object, without any explicit initialization, you must create a Bbox default constructor.


Now remember that an array have a size that is fixed at the time of compilation. They also tend to decay to pointers when least wanted.

If you need a dynamic "array" whose size doesn't have to be known at compile-time, and where you can add or remove elements at run-time, you should use std::vector:

std::vector<Bbox> list;

You can initialize it just like for arrays, or add elements later when needed:

list.emplace_back(some_x, some_y);

As a vector is an "object", it's also easy to pass copies of it to function, or passing references if you have a lot of elements in it. It keeps track of its own size, you can easily loop over a vector, and use many of the nice algorithms available in the standard library. Well you can do this with array, and even pointers, but it's easier with a vector.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3