1

I have something of this nature:

SomeClass {
public:
     union {
         int m_256[256];
         int m_16[16][16];
         int m_4[4][4][4][4];
     }

    SomeClass() {
        // Initialize Array to some default value
        for ( unsigned u = 0; u < 256; u++ ) {
            m_256[u] = 0;
        }
    }         
};

With the understanding of unions the for loop within the constructor will initialize m_256 to all 0s and the other 2 arrays are just another version or alias of it, so those arrays should be initialized as well since the memory size is exactly the same and the memory is shared.

I'd prefer not to go through a for loop to initialize all values of the array to some default value. Also since there are 3 arrays within this union, you can only have 1 non static member with an initialize list within a union. So this is valid.

union {
    int m_256[256]{};
    int m_16[16][16];
    int m_4[4][4][4][4];
}

Instead of using the for loop within the constructor or typing the same number manually 256 times, is there a short hand method that will initialize all values within the array to the same initial value?

EDIT

Based on a comment from user657267 he said:

Keep in mind that technically you can't write to one union member and read from another

Consider this: without making any changes to the class above and simply adding this operator overload:

std::ostream& operator<<( std::ostream& out, const SomeClass& s ) {    
    out << std::endl;

    out << "{Box, Slice, Row, Column}\n";
    for (unsigned box = 0; box < 4; box++) {
        for (unsigned slice = 0; slice < 4; slice++) {
            for (unsigned row = 0; row < 4; row++) {
                for (unsigned col = 0; col < 4; col++) {
                    out << "(" << box << "," << slice << "," << row << "," << col << ") = "
                        << s.m_4[box][slice][row][col] << std::endl;
                }
            }
        }
    }
    return out;
} // operator<<

Now in the main function we can do this.

int main() {
    SomeClass s;

    // Initialize This Array To Have Each Value Incremented From 0 - 255
    for ( unsigned u = 0; u < 256; u++ ) {
        s.m_256[u] = u;
    }

    // Print Out Our Array That Is In The Union Using The Overloaded Operator.
    // Note The Overloaded Operator Is Using The declaration of m_p4 and not m_p256
    std::cout << s << std::endl;

    // Now We Know That If You Extract A Value From Any Given Index It Will Return That Value. 
    // So Lets Pull Out Two Random Values From Using The Other Two Members of the Union.
    int A = s.m_4[0][2][1][3];
    int B = s.m_16[12][9];

    // Now Print Out A & B
    std::cout << A << ", " << B << std::endl;

    return 0;
}

Other than the printed array table the last two values are:

39, 201

Now if we scroll through the table and look for (0,2,1,3) the value is 39 and to test out if 201 is correct; we used [12][9]. If you are using a double for loop to index a flat array the indexing is equal to (i * num_j + j ) so, knowing that the 2D Array Version of this 1D or 4D array is [16][16] in size we can calculate this value mathematically: 12 * 16 + 9 = 201.

Within my specific case doesn't this invalidate his statement? In c++ are unions not the sharing of memory between two variables, and if you have the same data type such as int & int doesn't this make them alias of one another? I was surely able to initialize the 1D flat array, use the 4D version to print a table, and was able to extract values from both the 2D & 4D versions.

Edit

I know what others are saying about you can't write to one and access another technically because of a case as such:

union foo {
    int x;
    char y;
};

Here is an excellent answer to a different question on unions Difference Between Structs & Unions. However, in my case here, the data type and the size in memory for all three arrays are the same. Also, if one value is changed in one I am expecting it to change in another. These are just different ways to access the same memory. Eventually this "nameless union" will be a private member within my class, and there will be public methods to retrieve a const reference to the full array, to retrieve the contents from the arrays by index values from each of the 3 types, and to place contents into the array by any of the three types.

All the boiler plate will be done behind the scenes in private. So I do not see this as in issue, and the behavior here is what I am after. It is not as if I'm creating an instance of a union where it is mixed types. I'm not doing bit fields with them. I'm basically conserving memory so I don't have to have 3 arrays that are 256 x (size of element) then have to have a bunch of copying from one array to another array semantics, this property of how unions work, is what I'm actually after. It is 1/3 the amount of memory used by a single instance of the class in use, probably 20% faster and more efficient without having to keep 3 different independent arrays synchronized every time an element is added or removed, or moved within the array.

As structs are defined: They will allocate enough memory for every data type and instance within the struct. You can set each data type independently

As unions are defined: They will allocate enough memory for the largest data type within the union. If you set one data type, it will change the other data type.

In the context of my class, the union is nameless so you can not create an instance of it, however you can access any of its members. In the case here with these three arrays:

 byte a[256];         // 256 bytes
 byte b[16][16];      // 16 x 16 = 256 bytes
 byte c[4][4][4][4];  // 4^4 = 256 bytes

They are exactly the same size; and in my all three of these are the same array in my class. This is used to access the data in different ways.

Community
  • 1
  • 1
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • what about `memset` ? Or you want to avoid loops completely? – Giuseppe Pes Apr 06 '16 at 08:18
  • 1
    There's no shorthand for initialising array elements to anything except 0. – molbdnilo Apr 06 '16 at 08:26
  • 2
    Keep in mind that technically you can't write to one union member and read from another. – user657267 Apr 06 '16 at 08:30
  • I haven't used arrays in a while, been using std containers for most of my classes that'll hold many instances of objects and manages them, but now I'm in the process of creating a generic data structure that has a predefined container and now I'm revisiting arrays and raw pointers again. I don't want the overhead of the std library containers if possible. – Francis Cugler Apr 06 '16 at 08:45
  • @molbdnilo I didn't think there was thank you for clarifying that; but the good part is that 0 is the initial value to use just to make sure there isn't junk in the array. I'm trying to remember if using an open and closed brace after the declaration of the array will initialize all of its elements to 0. – Francis Cugler Apr 06 '16 at 08:48
  • 1
    regarding the edit, "Doesn't this invalidate his statement? " - no it doesn't. Your code causes undefined behaviour. Sometimes this means the code appears to work like you expect. Union aliasing is not defined in Standard C++ – M.M Apr 07 '16 at 04:32
  • Okay, but I've never once had problems with it. Not at least on a windows machine using VS and I've always used Intel processors. – Francis Cugler Apr 07 '16 at 05:20
  • @FrancisCugler The fact that you didn't have problems with it doesn't mean that they won't appear at some point in the future. Undefined behaviour, by definition, might manifest itself as a program perfectly working as well. Doesn't mean you should rely on that behaviour without *a very good reason* to do so, which I believe isn't the case here. Hence my downvote. – Bartek Banachewicz Apr 07 '16 at 10:59

1 Answers1

2

The loop is certainly an overkill:

std::fill(std::begin(m_256), std::end(m_256), 42); // fills with 42

Other than that, no built-in language construct; it'd amount to pretty much the same as the above, though.

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • I like the answer and is a good method for other uses, but trying to stay away from std:: as much as possible on this one. – Francis Cugler Apr 06 '16 at 10:14
  • 2
    @FrancisCugler And what purpose could "staying away from `std::`" possibly serve? – Bartek Banachewicz Apr 06 '16 at 10:14
  • I don't want the overhead of std. The data structure I'm working on has a balance between being simple with some complexity. For what it is and needs to do doesn't need to rely on the std library except for maybe in the case of smart pointers – Francis Cugler Apr 07 '16 at 01:39
  • 3
    There is no overhead of `std::fill`. It may be faster than alternatives. – M.M Apr 07 '16 at 04:31
  • @M.M. kk i'll keep that in mind. I do know a good portion of the std namespace, but there is still a lot about it that I don't know. I haven't really used `std::fill` enough to know about its capabilities of efficiency. But as for my reply to Bartek Banachewicz I was referring to the their containers. My data structure is specific to my needs, I only need an array of [256] elements for my purposes. I basically have a 16x16 table that can be represented either as a single flat array, or an array of 4 cubes where the cells in the cubes are 4x4x4. ... – Francis Cugler Apr 07 '16 at 06:21
  • @M.M (...continued) I could of easily made a struct or a class type with 3 of the same data types, then just had an array of 4, but that is not what I'm after because this array in the union is also associated with two other arrays `byte table[256]` struct T{ byte, byte }; T t[256] where these two are the predetermined lookup table. The first array is a compressed version of the second array as the second array is the grid coordinates. This predefined lookup table is what will be used or referenced to insert and retrieve data from the array in the union. These arrays are in a separate class. – Francis Cugler Apr 07 '16 at 06:26
  • @M.M (...continued) the first class that has the union also has a referenced pointer to my table class, and my table class is a singleton object where once an instance is created, the table is automatically generated and my table has a static get method to retrieve a static reference pointer. The table class has methods only to retrieve both arrays (compressed & coordinate indexes), a display function for each, and a function to retrieve coordinate pairs from an index value. – Francis Cugler Apr 07 '16 at 06:32
  • @FrancisCugler This sounds like a terrible design. Global variables are pretty much universally regarded a bad programming practice nowadays. Anyway, there's absolutely no reason to *not use* `std::fill` or any other algorithm *unless* you prove that it's not enough for your purposes. Using `std` should be the default choice, not the manual loops. – Bartek Banachewicz Apr 07 '16 at 11:01
  • How are these variables global as they belong to a class? – Francis Cugler Apr 07 '16 at 17:18
  • I'll have to bench mark the differences between the loop and std::fill(). The loop should not be overkill since there are only 256 elements. If a computer today can not do that in less than a fraction of a second, then the computer is out dated. I could understand if you had an array where the number of elements were at the max size of the largest value of unsigned int either on a 32bit or 64bit system. Then if you were to iterate over millions or billions of fields then yes use std::fill() or a derived modified version of it would be all good. – Francis Cugler Apr 07 '16 at 17:21
  • @FrancisCugler the problem with the loop is that it's an error-prone, low-level, more complex construct than `std::fill`, which serves one well-defined purpose - filling things with a value. – Bartek Banachewicz Apr 08 '16 at 13:10
  • @Bartek Banachewicz yes, but they won't necessarily be holding values. They will more than likely be holding holding shared pointers. – Francis Cugler Apr 09 '16 at 19:30