1

I am trying to create an nxn array of objects, but I do not know where to call their constructors. Here is my code:

class obj {
  private: int x;
  public:  obj( int _x ) { x = _x; }
};

int main( int argc, const char* argv[] ) {

  int n = 3; //matrix size    

  obj** matrix = new obj*[n];
  for( int i = 0; i < n; i++ )
    matrix[i] = new obj[n];

  return 0;
}

3 Answers3

3

If only the default constructor invocation is required, your code already calls it.

For a non-default constructor add a nested loop, like this:

for( int i = 0; i < n; i++ ) {
    matrix[i] = new obj[n];
    for (int j = 0 ; j != n ; j++) {
        matrix[i][j] = obj(arg1, arg2, arg3); // Non-default constructor
    }
}

A better approach is to use std::vector of obj if no polymorphic behavior is required, or of smart pointers to obj if you need polymorphic behavior.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • is it necessary to use the second loop in your snippet? this line `matrix[i] = new obj[n];` itself allocates `n` objects of class `obj`, and by doing that `n` times it allocates a full nxn matrix – mangusta Feb 19 '14 at 14:05
  • @mangusta You are right, I miscounted the number of asterisks, thinking that OP has a matrix of pointers when in fact he does not. Thanks! – Sergey Kalinichenko Feb 19 '14 at 14:13
  • oh, so for non-default constructor, we should create an object element-wise ? can't we do it in array allocation like `obj()[]`? i haven't heard about that, so i'm asking just to make things clear :) – mangusta Feb 19 '14 at 14:16
  • @mangusta [There was a question about this on Stack Overflow](http://stackoverflow.com/a/2409853/335858). Unfortunately, there is no syntax for doing it without a loop. – Sergey Kalinichenko Feb 19 '14 at 14:19
0

If you really want to muck around with low-level memory management, then you can't - the array form of new doesn't allow you to pass arguments to the objects' constructors. The best you could do is to let them be default-constructed (adding a constructor to your class if necessary) and then loop through and reassign them. This is tedious and error-prone.

I'd suggest using higher-level classes; for dynamic arrays, use a vector:

std::vector<std::vector<obj>> matrix(n);
for (auto & row : matrix) {
    row.reserve(n);
    for (size_t i = 0; i < n; ++n) {
        row.emplace_back(/* constructor argument(s) here */);
    }
}

As a bonus, RAII means you don't need to delete all the allocations yourself, and it won't leak memory if any of this fails.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • As a matter of fact, you can construct the array elements in place with placement new syntax (see my answer). – cmaster - reinstate monica Feb 19 '14 at 14:27
  • @cmaster: Indeed, you could go further down the rabbit-hole of manual memory management and essentially reinvent `std::vector` (remembering to explicitly destroy each object, in addition to freeing the memory, once you've finished with it). I wasn't going to suggest that myself though - it will lead to insanity. – Mike Seymour Feb 19 '14 at 14:31
0

dasblinkenlight has already given quite a good answer, however, there is a second way to do it that's more efficient. Because, if you do (the code is taken from his answer)

matrix[i] = new obj[n];
for (int j = 0 ; j != n ; j++) {
    matrix[i][j] = obj(arg1, arg2, arg3); // Non-default constructor
}

the following will happen:

  1. Memory for n objects is allocated.

  2. All n objects are default constructed.

  3. For each object, a new object is custom constructed on the stack.

  4. This object on the stack is copied into the allocated object.

  5. The object on the stack is destructed.

Obviously much more than would have been necessary (albeit perfectly correct).

You can work around this by using placement new syntax:

matrix[i] = (obj*)new char[n*sizeof obj];    //Allocate only memory, do not construct!
for (int j = 0 ; j != n ; j++) {
    new (&matrix[i][j]) obj(arg1, arg2, arg3); // Non-default constructor called directly on the object in the matrix.
}
cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106