14

I had the following code:

#include <iostream>

struct T
{
   int a, b, c;
};

int main()
{
   T t = {0};
   std::cout << t.a << ',' << t.b << ',' << t.c << '\n';
}

Output:

0,0,0

After many years of this code running happily in a critical production environment, serving a vital function, the requirements of the project changed and I needed the output to be 1,1,1.

So, I changed {0} to {1}:

#include <iostream>

struct T
{
   int a, b, c;
};

int main()
{
   T t = {1};
   std::cout << t.a << ',' << t.b << ',' << t.c << '\n';
}

Output:

1,0,0

I expected 1,1,1 instead.

Why are my struct's members not all being initialised properly?

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • @Matthieu: Why the C++-faq tag? – Alok Save Feb 10 '13 at 12:59
  • 2
    Not the one to downvote but seems people *don't like your question*, which is not a good enough reason to downvote but people do that rampantly here in SO.Also, downvoting a question doesn't cost you any rep, so it is a freebie which everyone wants to enjoy.Notice only the Q is being downvoted not the answer(*downvoting answers cost rep*).The only question i have here is why this is tagged as c++-faq? Is this a frequently asked question in SO? Are there no existing answers which explain this already to qualify as faq? I don't see any bad in the Q I don't see the reason for it being a faq. – Alok Save Feb 10 '13 at 13:07
  • 3
    I think people are _still_ not getting that _[writing your own question](http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/) [and answer is encouraged](http://meta.stackexchange.com/questions/17463/can-i-answer-my-own-questions-even-those-where-i-knew-the-answer-before-asking/17467#17467)_, despite the fact that there is an "answer this question" box on the question posting page. The mind really does boggle. I'm just writing an in-depth Q&A to help other people, for free, on my weekend. – Lightness Races in Orbit Feb 10 '13 at 13:08
  • 2
    @AlokSave: I have seen the initialization with `{0}` recommended a couple time, and it does carry a bit of strange semantic. I thought it would be helpful to tag it so. – Matthieu M. Feb 10 '13 at 13:13
  • @MatthieuM.: I agree its a strange and important semantic but I believe the common practice/procedure followed is to find existing accurate answers and tag them to be a faq rather than create new faq entries. Doesn't the marked duplicate(*and probably many others*) explain this in accurate detail already? Why would this qualify as a faq and not those many others? – Alok Save Feb 10 '13 at 13:18
  • @AlokSave: I'm not convinced that that's really an appropriate duplicate. If nothing else, it's insufficiently abstract for a FAQ post. And I see no problem forming new FAQ posts; do you think that my answer is not "accurate"? It's certainly "existing". Regardless, this discussion should take place in the lounge. – Lightness Races in Orbit Feb 10 '13 at 13:20

1 Answers1

32

When you write = {0}, that only explicitly initialises the first member; the rest are zero-initialised implicitly according to the standard, so it appears at first glance that you explicitly initialised all members with the 0 that you wrote, but you didn't.

That place where you wrote 0 only affects the first member. So when, one day, you changed it to 1 thinking that it'll change all members, you'll have a bug, like here. It's misleading/dangerous/silly/fragile code.

For that reason, without an accompanying explanatory comment, = {0} will not pass code review in my team. You should originally have written:

T t = {};

And now, to solve your problem according to the new requirements, you should write:

T t = {1,1,1};

or, if you don't mind your struct potentially losing POD-ness, give T a constructor.


Formal wording

[C++11: 8.5.1/2]: When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause. If the initializer-clause is an expression and a narrowing conversion (8.5.4) is required to convert the expression, the program is ill-formed. [..]

[C++11: 8.5.1/6]: An initializer-list is ill-formed if the number of initializer-clauses exceeds the number of members or elements to initialize.

[C++11: 8.5.1/7]: If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list (8.5.4).

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 12
    In C (as opposed to C++), the `= { 0 }` notation is ancient tradition for initializing all fields to zero. Some versions of GCC warn about 'incompletely initialized structure' when given the appropriate options (e.g. 4.1.x through 4.6.x); more recent versions (e.g. GCC 4.7.1) recognize `= { 0 }` as a special case and don't generate the warning when that notation is used. One reason for using the abbreviated notation is to avoid having to change the initializer as the structure changes. (I'm not about to pontificate on how this applies to C++.) – Jonathan Leffler Feb 10 '13 at 14:13
  • So how would I manage to make them all become initialised to 1 without looping? – David G Mar 22 '13 at 01:02
  • @David: Can't. And you can't loop over them, anyway. – Lightness Races in Orbit Mar 22 '13 at 10:19