C++: multidimensional array initialization in constructor

21,983

Solution 1

If you have C++11, you can use this syntax in the constructor definition:

A() : a{{1,2}, {3, 4}} {}

If you don't have C++11, you will need to stick to the wicked old ways:

A() {
  a[0][0] = 1;
  // etc
}

The first example also uses the constructor init-list, which should always be used to initialize members instead of intializing them in the constructor body.

Solution 2

various multidimensional array in constructor by example:

// int array1[1];
A() : array1{0} {}

// int array2[2][2];
A() : array2{{0}} {}

// int array3[3][3][3];
A() : array3{{{0}}} {}

Solution 3

Try this, it works for bidimensional array (in standard C++):

 class A {
 public:
  int a[2][2];
  A();
};


typedef struct{ int a[4]; } array_t;

A::A() {

 int at[2][2] = {{1,2},{2,4}};

*(array_t*)a = *(array_t*)at;

}

Ciao Angelo

Share:
21,983
ravenfrost
Author by

ravenfrost

Updated on August 08, 2022

Comments

  • ravenfrost
    ravenfrost almost 2 years

    I want to use a two dimensional array of constant size as a class member in C++. I have problems initializing it in the constructor though.

    Here are my non-working tries:

    1.)

    class A {
     public:
      int a[2][2];
      A();
    };
    
    A::A() {
    a = {{1,2},{2,4}};
    }
    

    yields: error: assigning to an array from an initializer list

    2.)

    class A {
     public:
      int a[2][2];
      A();
    };
    
    A::A() {
    int b[2][2] = {{1,2},{2,4}};
    a = b;
    }
    

    yields: invalid array assignment

    3.)

    class A {
     public:
      int **a;
      A();
    };
    
    A::A() {
    int b[2][2] = {{1,2},{2,4}};
    a = b;
    }
    

    yields: cannot convert ‘int [2][2]’ to ‘int**’ in assignment

    I come from C background. I know that I could use std::vector and I am aware of the disadvantages this approach has but since this is an exercise for me I would like to know how to get it working with plain arrays. I should add that I want to work on this array later on. I want to change the stored values but not the size. Maybe that matters as well (I figured a const at the right place could help somehow?).

  • pmr
    pmr about 10 years
    This is a gcc GNU extension. Drop the outer parens.
  • Constructor
    Constructor about 10 years
    @pmr Thank you. Actually it was a typo. :-)
  • Cheers and hth. - Alf
    Cheers and hth. - Alf about 10 years
    As I understand it, the syntax used here is non-standard, a g++ language extension.
  • pmr
    pmr about 10 years
    @Cheersandhth.-Alf I tested this with both gcc and clang using -std=c++11 (opposed to std=gnu11) and both accepted it. clang rejected a({{1,2}, {3, 4}}) though as a GNU extension.
  • Constructor
    Constructor about 10 years
    @Cheersandhth.-Alf Try to compile this code and your one with -pedantic-errors flag and...
  • Kahler
    Kahler about 10 years
    I've been using this for a while in GCC, thinking it was standard. Good to know. (Will try not to comment that I really think this should be standardized. Ops, did.)
  • Cheers and hth. - Alf
    Cheers and hth. - Alf about 10 years
    @Constructor: I think I'm wrong BUT my code compiles just fine with g++ 4.8.2 and option -pedantic-errors. However, Visual C++ 2013 reports "error C2536: 'A::A::m' : cannot specify explicit initializer for arrays". So in a practical sense the C++11 notation (if it is standard, which I now believe after checking and finding no language stating the opposite) is not yet portable.
  • Constructor
    Constructor about 10 years
    @Cheersandhth.-Alf Really? g++ 4.8.1 diagnoses it as incorrect code with -pedantic-errors.
  • M.M
    M.M about 10 years
    In C++11 you could just have in the class definition int a[2][2] = { {1,2}, {3,4} };
  • Constructor
    Constructor about 10 years
    @Cheersandhth.-Alf As I can see there is a bug in VC++ (even in VC++2013).
  • pmr
    pmr about 10 years
    @MattMcNabb Yes, but I think in class definitions are something that should never been added to the standard in the first place and that you shouldn't ever use it.
  • M.M
    M.M about 10 years
    They have their place, they can simplify code that was convoluted otherwise. They do break interface/implementation separation though - although the concept of private and protected member variables also break that.
  • M.M
    M.M about 10 years
    I think the assignment is undefined behaviour, although you could save the situation by using a memcpy or equivalent.
  • pmr
    pmr about 10 years
    @MattMcNabb They also break the rule that I need to look at the ctors to understand the invariants of a class after construction. Now I need to look everywhere.
  • M.M
    M.M about 10 years
    You have to look at the variables anyway, a ctor might neglect to initialize them (so they have uninitialized values sometimes).
  • AngeloDM
    AngeloDM about 10 years
    This technique forces the compiler to use the assignement operator for above array (supported for standard structures). Naturally, this is only valid when the size of the operands are equal. I use this example to show the power of the casting of the C language. However, I accept your comment and I will make a new question about this argument, so we can have other opinions about aove code. Thanks.
  • M.M
    M.M about 10 years
    The UB comes in before you get that far. It is undefined to alias a struct as an int[2][2]. (The Standard lists which types may be aliased with which types and this is not in the list). Further, it's possible that at may not be correctly aligned for array_t * (I'd have to check the wording of the alignment requirements to verify this)
  • AngeloDM
    AngeloDM about 10 years
    I welcome your comments and I modified my solution, please tell me if you think that the new solution is more portable. Thanks.
  • ravenfrost
    ravenfrost about 10 years
    Just for me and the sake of complete understanding: Doing so would render **a NULL after the constructor has ended right? I'm not exactly a pro in C either.
  • ravenfrost
    ravenfrost about 10 years
    Since I just g++ I will go with that. Thanks a bunch.
  • Kahler
    Kahler about 10 years
    No, no. The analogy is that b only exists inside where it was declared (the constructor) so if you take it's address, when the function ends, a will still have whatever value it was, but we can't guarantee what will lies there. The program may use that address for another purpose. Most likely, if you later try to access what a points to outside the function, an error about invalid memory will pop up, or some unreliable value will be read.
  • ravenfrost
    ravenfrost about 10 years
    Okay, I see now. Thank you for clearing that up for me.