Tutorial :populating int array that is a member variable



Question:

I'm using C++ to create a tile map for a game. My problem is, I want to populate a multidimensional array of ints in the Map constructor, but it's not working properly. Here's my code in "Map.h" (irrelevant code has been removed).

class Map {    private:      int mapArray[15][20];    };  

And my code from Map.cpp

Map::Map()  {        mapArray = {          { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 },          { 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 },          { 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59 },          { 60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79 },          { 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99 },          { 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119 },          { 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139 },          { 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159 },          { 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179 },          { 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199 },          { 200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219 },          { 220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239 },          { 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259 },          { 260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279 },          { 280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299 }      };      }  

PS. creating the mapArray locally, within a member function using int mapArray[15][20] and populating it then is working fine, I just can't seem to get it to populate in the constructor, with a member variable.

PPS. Very rusty with C++, please be gentle.

What am I doing wrong?

Thanks, James.


Solution:1

You can't use array initializers like that in a class constructor. Members can only be initialized by using the initializer list. Your best bet is to load this data from a file, or to declare the array as static.

class Map  {  private:  static int mapArray[15][20];  /* ... */  };  

Then define storage for the static array in a source file (.cpp), also known as a translation unit:

int Map::mapArray[15][20] = { ... };  


Solution:2

You should be able to do something like this:

class Map  {    int mapArray[15][20];      public:    Map() : mapArray( (int[15][20]) {      { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 },      { 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 },      { 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59 },      { 60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79 },      { 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99 },      { 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119 },      { 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139 },      { 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159 },      { 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179 },      { 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199 },      { 200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219 },      { 220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239 },      { 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259 },      { 260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279 },      { 280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299 }    } )    {    }  };  

Note that this initialization style is part of C99 and may not be included with your compiler or may not work for C++. Works on GCC 4 for me.

Also note that I did not compile this code. I adapted it for your case from some other code of mine that does work though.


Solution:3

You can use the brace syntax only for initialization.

When your constructor is executed, the array member has alredy been created.


Solution:4

Unfortunately, there's no syntax to do literally that in C++ for member non-static arrays. You can assign the initial values to array members one-by-one, but that's, of course, is quite cumbersome.

If the array values are the same in all objects of that class, then you probably need a static member array. See the answer from Mads then.

If you really need a non-static member array, meaning that you want to be able to "customize" the contents of the array on per-object basis by modifying it later or by initializing it differently, then you can try doing this

class Map {    static const int MapArrayInit[15][20];    int MapArray[15][20];    public:    Map()     {      assert(sizeof MapArray == sizeof MapArrayInit); // better: STATIC_ASSERT      std::memcpy(MapArray, MapArrayInit, sizeof MapArray);      // Now you can customize MapArray to your liking    }  };  

and in one of the implementation files

const int Map::MapArrayInit = { /* whatever */ };  

This will require extra memory for MapArrayInit, but since you are instatiating a separate MapArray in each instance of Map anyway it is not a big deal.

If you don't want to modify your MapArray after initialization but still want to have several different versions of MapArray contents in different instances of `Map', you can use the following approach

class Map {    static const int MapArrayInit1[15][20];    static const int MapArrayInit2[15][20];    static const int MapArrayInit3[15][20];    const int (&MapArray)[15][20]; // or a pointer    public:    Map() : MapArray(MapArrayInit1) /* or 2, or 3 */    {    }  };  

and in one of the implementation files

const int Map::MapArrayInit1 = { /* whatever */ };  const int Map::MapArrayInit2 = { /* whatever */ };  const int Map::MapArrayInit3 = { /* whatever */ };  

Choose whatever works best for you.


Solution:5

You can only use curly brace syntax if you're initializing the array at declaration. In your constructor, you're not. You probably want to load map data from a file anyways instead of hard coding.


Solution:6

This is an assignment, not an initialization. Simple brace initializers only work during initialization. Use the compound literal syntax, which resembles a typecast (to the aggregate you want to initialize) followed by a brace initializer.

Map::Map()  {        mapArray = (int[15][20]) {          { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 },          { 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 },          { 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59 },          { 60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79 },          { 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99 },          { 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119 },          { 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139 },          { 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159 },          { 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179 },          { 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199 },          { 200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219 },          { 220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239 },          { 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259 },          { 260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279 },          { 280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299 }      };      }  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »