10

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?).

5 Answers 5

11

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.

Sign up to request clarification or add additional context in comments.

13 Comments

As I understand it, the syntax used here is non-standard, a g++ language extension.
@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.
@Cheersandhth.-Alf Try to compile this code and your one with -pedantic-errors flag and...
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.)
@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.
|
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}}} {}

Comments

1

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

4 Comments

I think the assignment is undefined behaviour, although you could save the situation by using a memcpy or equivalent.
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.
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)
I welcome your comments and I modified my solution, please tell me if you think that the new solution is more portable. Thanks.
0

Your first variant is extremely close to the right C++11 syntax:

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

2 Comments

This is a gcc GNU extension. Drop the outer parens.
@pmr Thank you. Actually it was a typo. :-)
0

To complement the previous answers (you guys are so fast):

What you were trying to do in case 1 and 2 is array assignment, not permitted, as compiler says ;

But I would like to draw your attention to your third case, that's a grave misconception, specially coming from C as you say.

Assigning to a a pointer to a local variable?

3 Comments

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.
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.
Okay, I see now. Thank you for clearing that up for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.