C++: multidimensional array initialization in constructor
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
ravenfrost
Updated on August 08, 2022Comments
-
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 aconst
at the right place could help somehow?). -
pmr about 10 yearsThis is a gcc GNU extension. Drop the outer parens.
-
Constructor about 10 years@pmr Thank you. Actually it was a typo. :-)
-
Cheers and hth. - Alf about 10 yearsAs I understand it, the syntax used here is non-standard, a g++ language extension.
-
pmr about 10 years@Cheersandhth.-Alf I tested this with both gcc and clang using
-std=c++11
(opposed tostd=gnu11
) and both accepted it.clang
rejecteda({{1,2}, {3, 4}})
though as a GNU extension. -
Constructor about 10 years@Cheersandhth.-Alf Try to compile this code and your one with
-pedantic-errors
flag and... -
Kahler about 10 yearsI'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 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 about 10 years@Cheersandhth.-Alf Really? g++ 4.8.1 diagnoses it as incorrect code with
-pedantic-errors
. -
M.M about 10 yearsIn C++11 you could just have in the class definition
int a[2][2] = { {1,2}, {3,4} };
-
Constructor about 10 years@Cheersandhth.-Alf As I can see there is a bug in VC++ (even in VC++2013).
-
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 about 10 yearsThey 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 about 10 yearsI think the assignment is undefined behaviour, although you could save the situation by using a
memcpy
or equivalent. -
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 about 10 yearsYou have to look at the variables anyway, a ctor might neglect to initialize them (so they have uninitialized values sometimes).
-
AngeloDM about 10 yearsThis 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 about 10 yearsThe 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 thatat
may not be correctly aligned forarray_t *
(I'd have to check the wording of the alignment requirements to verify this) -
AngeloDM about 10 yearsI welcome your comments and I modified my solution, please tell me if you think that the new solution is more portable. Thanks.
-
ravenfrost about 10 yearsJust 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 inC
either. -
ravenfrost about 10 yearsSince I just g++ I will go with that. Thanks a bunch.
-
Kahler about 10 yearsNo, 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 whata
points to outside the function, an error about invalid memory will pop up, or some unreliable value will be read. -
ravenfrost about 10 yearsOkay, I see now. Thank you for clearing that up for me.