Mar 8, 2015

Aggregate initialization

A couple of days ago, I ran into some legacy code, which basically said
Person person = {};
I hadn't really been dealing with this type of initialization before, so I had to look it up. I learned it is called aggregate initialization, and that's the topic for this post. I'm using WinDbg, Visual Studio Express 2010 and compiling in debug mode. Note also that this discussion does not take C++11 into account.

Let's say you have a struct like this.
struct Person
{
   char* name;
   int age;
   bool employed;
};
Before proceeding, we need to know what an aggregate is.
Here is the definition from C++03.
An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).
So the struct Person is an aggregate, which is a condition for the aggregate initialization to work.

So what does this piece of code do?
Person person = {};
I've learned that this initialization says (in this particular case) that all members in the struct will be zero-initialized.

Before proceeding with the aggregate initialization, just a quick note what may happen if you forget to initialize the struct.
The code below, will result in a struct with indeterminate values, and we get a runtime error message when executing the program.

Person person;
printf("%s, %d, %d", person.name, person.age, person.employed);



Well, back to aggregate initialization.

If we execute this piece of code, we will see that the members are zero-initialized.
#include <cstdio>

struct Person
{
   char* name;
   int age;
   bool employed;
};

int main()
{
   Person person = {};
   printf("%s, %d, %d", person.name, person.age, person.employed);

   getchar();
   return 0;
}


Execution of the program above
Above, we say that we initialize Person with an empty initialize-list.

The struct Person can be initialized using a complete initialize-list, see the example below.
 
Person person = { "Kent", 24, true };
printf("%s, %d, %d", person.name, person.age, person.employed);

Execution of the program above

It is also possible to only initialize some of the members, the remaining will be zero-initialized. In the example below, the name- and age-member will be initialized, while the employed-member will be zero-initialized.

Person person = { "Kent", 24 };
printf("%s, %d, %d", person.name, person.age, person.employed);

Execution of the program above

Before ending this post, let's check out the stack from the last example. In the screenshot below, we have just executed the initialization.


Let's clarify what's going on above. The first instruction of interest is at the virtual address 0x009213DE in the disassembly view. As you can see, the struct's Person's name-member is initialized with a 32 bit pointer. This pointer (within the red box) points to the string literal "Kent" (which probably is within a read-only section in the memory).

Further, we see that the struct's Person's age-member is initialized with 18h, i.e. 24.

Finally, the last member in the struct Person, the employed-member, is zero-initialized, using the xor eax, eax instruction.

The stack is shown to the left, as you can see within the blue box, the current stack frame (EBP) start at virtual address 0x0025FA14. The boxes in the stack view shows where the Person's member are located and its values.

You are welcome to leave comments, complaints or questions!