0

Given a struct like

struct Square
{
  Square(Color p_color): color_(p_color) {}
  Color color_;
 };

how can i declare a two dimensional array and later initialize it. For example,

typedef Square (&Square8x8)[8][8];

Square8x8 initSquares()
{
    Square board[ROWS][COLS]; //declare the array

    for(int row=0;row<ROWS;row++)
            for(int col=0;col<COLS;col++)
            {
                    if(col%2 == 0)
                            board[row][col]= Square(WHITE); //actual initlization
                    else
                            board[row][col] = Square(BLACK);
            }
    return board;

 }
Jimm
  • 8,165
  • 16
  • 69
  • 118
  • 2
    You can't. A constructor must be called for each element in the array. – juanchopanza May 25 '13 at 12:24
  • 1
    The whole point of a constructor is that you cannot bypass it. – Niels Keurentjes May 25 '13 at 12:26
  • If preallocating memory is your requirement, then you should look up placement `new` and there too eliding constructor isn't an option but you can handle the memory (de)allocation. – legends2k May 25 '13 at 12:49
  • Since you are actually allocating `ROWS*COLS` `Square` elements they need to be properly constructed. Do you want to use your existing constructor instead of a default constructor? – Andrei May 25 '13 at 12:51

4 Answers4

4

You misunderstand the point of a constructor, which is to ensure an object is always initialized and valid during its entire lifecycle. Thus the invocation of a constructor cannot be in any way delayed or postponed.

It's a typical XY-problem though - you're asking for help with an intended solution, not a problem. The real problem is that you don't want to postpone the constructor, but initialize it later on. Construction and initialization are related subjects, but not identical.

The best solution is to give your class a setColor or initialize function, separate from the constructor. An alternative solution (which is closer to your question) is to declare the array not as objects, but as pointers, and then really instantiate the object later on with new Square(WHITE). I'd go for the first though, the second requires a lot more lifecycle control with explicit deletion.

Community
  • 1
  • 1
Niels Keurentjes
  • 41,402
  • 9
  • 98
  • 136
  • 1
    +1, clearly an XY problem. Another solution is to have an array of `boost::optional` or `std::optional` objects. – juanchopanza May 25 '13 at 12:33
  • +1 for the STL additions, my answer is based on 'raw' C++, but using STL containers will simplify lifecycle management. – Niels Keurentjes May 25 '13 at 12:34
  • 1
    The original problem seems to be http://stackoverflow.com/questions/16749103/how-to-declare-two-dimensional-array-of-objects-and-return-it-from-a-function – Andrei May 25 '13 at 12:52
1

You need a default constructor for Square which is able to call without parameters. For example:

struct Square
{
  Square() {}  // <------------------------- For example
  Square(Color p_color): color_(p_color) {}
  Color color_;
};

Otherwise, you should use pointer to Square and new them later. For example:

struct Square
{
  Square(Color p_color): color_(p_color) {}
  Color color_;
};
const int ROWS = 8;
const int COLS = 8;

In this case, you should use pointers:

std::unique_ptr<Square> board[ROWS][COLS];

for (int i=0; i<ROWS; i++)
    for (int j=0; j<COLS; j++)
        board[i][j] = std::unique_ptr<Square>(new Square(RED));

or (for bare pointers)

Square* board[ROWS][COLS];

for (int i=0; i<ROWS; i++)
    for (int j=0; j<COLS; j++)
        board[i][j] = new Square(RED);

....
// Be careful, you should delete them all 
masoud
  • 55,379
  • 16
  • 141
  • 208
  • But i really do not want user to construct an empty Square.. Is there a way to do it without default constructor? – Jimm May 25 '13 at 12:26
  • So something like Square * board[ROWS][COLS]; – Jimm May 25 '13 at 12:28
  • OP is asking how to create an array of objects without calling a constructor, not how to implement a default constructor. – juanchopanza May 25 '13 at 12:30
  • If i have to return Square * board[ROWS][COLS] from a function, what should the function signature look like? – Jimm May 25 '13 at 12:33
  • @Jimm: I've put it. check it out. – masoud May 25 '13 at 12:35
  • but what would be the function signature? In particular, how to represent a return type which is clear in its intention. I would hate to return Square ****. Is there a way to typedef it to make it more clear? – Jimm May 25 '13 at 12:37
  • @Jimm 2D arrays are a pain. I would write a simple 2D matrix class, with sensible copy constructor, assignment operator and so on. Then you just return one of those by value. – juanchopanza May 25 '13 at 12:43
1

In case you don't want to use a default constructor you can use the constructor you already have.

This solution uses std::vector, which I also recommend you use.

std::vector<Square> myVector( ROWS*COLS, Square(WHITE) );

this will create an array of ROWS * COLS elements, each initialized to the value of Square(WHITE).

You could create a Board class, which uses such a vector inside and offers functionalities such as initializing a board of arbitrary size and indexing a Square in the linear vector based on Row and Column information.

You can also do:

Square board[2][2] = {Square(WHITE), Square(WHITE), Square(WHITE), Square(WHITE) };

but it doesn't really scale well.

Andrei
  • 4,880
  • 23
  • 30
0

Create an array of (smart) pointers instead of an array. One purpose of pointers is so objects can be initialized later.

djechlin
  • 59,258
  • 35
  • 162
  • 290