Suppose you have a large array or structure containing important information, and you want to initialize it to some default values in the beginning of the program. The following is not an optimal solution, it is quite tedious to type (what if the array is 500 elements long ?) Listing 1:

int arr[5];

arr[0] = 5;
arr[1] = 6;
arr[2] = 2;
arr[3] = 4;
arr[4] = 8;
We can write the same with a lot less typing ! But first, it is worthwhile to understand what an aggregate is. An aggregate is an array or a class with no user-declared constructors, no private or protected non-static data members, no base classes, and no virtual functions. Stated simply: just as its name suggests, an aggregate is a type meant to store data, usually without any other functionality. An aggregate can may be initialized using a brace-enclosed initialization list. Listing 2:

#include 

using namespace std;

int main()
{
    // Array initialization. Equivalent to
    // Listing 1
    //
    int arr[5] = {5, 6, 2, 4, 8};

    struct Foo
    {
        int a;
        int b;
    };

    // Structure initialization. Equivalent to:
    //
    // my_foo.a = 5;
    // my_foo.b = 6;
    //
    Foo my_foo = {5, 6};

    struct Bar
    {
        int a;
        int b;
        Foo bars_foo;

        int bar_arr[2];
    };

    // Aggregate initializations can be nested !
    // The following is equivalent to:
    //
    // my_bar.a = 5;
    // my_bar.b = 6;
    // my_bar.bars_foo.a = 6;
    // my_bar.bars_foo.b = 7;
    // my_bar.bar_arr[0] = 5;
    // my_bar.bar_arr[1] = 6;
    //
    Bar my_bar = {5, 6, {6, 7}, {5, 6}};

    return 0;
}
Note that brace-enclosed lists may be used in initialization only, not assignment. That is, only when the structs/arrays are declared. If you have to modify all values in an aggregate some time later, you'll have to use assignment, as demonstrated in Listing 1. There is an other aspect to aggregate initialization which can be very helpful sometimes: If some members of an aggregate are initialized, ALL of them are. If you supply only a partial initialization list, the rest will be initialized with zero. Listing 3:

#include 

using namespace std;

int main()
{
    // Partial initialization list. arr[0] is
    // initialized to 5, arr[1] to 6, and the
    // rest to 0
    //
    int arr[5] = {5, 6};

    for (int i = 0; i < 5; ++i)
        cout << "arr[" << i << "] = " << arr[i] 
               << endl;

    struct Foo
    {
        int a;
        unsigned b;
        float c;
        double d;
    };

    // Here is a convenient method to initialize
    // all members of a structure to 0
    //
    Foo my_foo = {0};

    cout << my_foo.a << endl << my_foo.b << endl
         << my_foo.c << endl << my_foo.d << endl;

    return 0;
}
As a final note, remember that only aggregate types may be initialized this way. For arrays this kind of initialization is quite useful (especially the quick all 0 initialization as demonstrated in Listing 3) but for more complex types (structs, classes) it is better to consider constructors. Update: The method suggested here may be dangerous when some members of the structure are complex classes (for example, the standard string class). These objects may not react well to direct memory initialization. Again, if your structure is complex, it is highly suggested to use a constructor - this way you can control the initialization, and only implement the code once (each instantiation of your structure will implicitly call the constructor).

Comments

comments powered by Disqus