105

If I needed to initialize only a few select values of a C++ struct, would this be correct:

struct foo {
    foo() : a(true), b(true) {}
    bool a;
    bool b;
    bool c;
 } bar;

Am I correct to assume I would end up with one struct item called bar with elements bar.a = true, bar.b = true and an undefined bar.c?

Joe Wilcoxson
  • 1,420
  • 3
  • 11
  • 21

4 Answers4

304

You don't even need to define a constructor

struct foo {
    bool a = true;
    bool b = true;
    bool c;
 } bar;

To clarify: these are called brace-or-equal-initializers (because you may also use brace initialization instead of equal sign). This is not only for aggregates: you can use this in normal class definitions. This was added in C++11.

Erik van Velzen
  • 6,211
  • 3
  • 23
  • 23
  • 139
    Downvoters: Please familiarize yourselves with the C++11 updates to the Standard before lecturing people on what is or isn't legal. [It actually compiles just fine.](http://ideone.com/lmYeem) This is C++11, and C++11 *is* C++, until a new version is adopted. – Ben Voigt May 28 '13 at 05:29
  • 9
    @jamesdlin: Since August 21, 2011, the `c++` tag means C++11. People are welcome to say C++98 or C++03 if they want to discuss an old version. And sometime next year, the bare `c++` tag will change again to mean C++14. – Ben Voigt May 28 '13 at 05:35
  • 11
    It's worth noting this immediately makes the type non-POD (verified via `std::is_pod::value`) and so, in that sense, is equivalent to writing a non-default constructor that sets the same values in an initialiser list. – underscore_d Dec 17 '15 at 21:47
  • 3
    Actually brace initialization is only allowed when there are no default member initializers in C++11. This limitation is lifted with C++14. ideone uses C++14 but if you use any C++11 compiler that code will fail. http://en.cppreference.com/w/cpp/language/aggregate_initialization – Giovanni Botta May 31 '16 at 21:55
  • What if the struct is defined using typedef, like C style? still initializes? – Dumbo Feb 11 '17 at 05:38
46

Yes. bar.a and bar.b are set to true, but bar.c is undefined. However, certain compilers will set it to false.

See a live example here: struct demo

According to C++ standard Section 8.5.12:

if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value

For primitive built-in data types (bool, char, wchar_t, short, int, long, float, double, long double), only global variables (all static storage variables) get default value of zero if they are not explicitly initialized.

If you don't really want undefined bar.c to start with, you should also initialize it like you did for bar.a and bar.b.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
taocp
  • 23,276
  • 10
  • 49
  • 62
12

You can do it by using a constructor, like this:

struct Date
{
int day;
int month;
int year;

Date()
{
    day=0;
    month=0;
    year=0;
}
};

or like this:

struct Date
{
int day;
int month;
int year;

Date():day(0),
       month(0),
       year(0){}
};

In your case bar.c is undefined,and its value depends on the compiler (while a and b were set to true).

Tcz
  • 661
  • 5
  • 18
  • 16
    There is no reason to prefer the first form. You should use initialization lists. – jamesdlin May 28 '13 at 03:51
  • 1
    @jamesdlin agreed in 99.9% of cases, where the 2nd is vastly preferable for countless reasons. however - just to play devil's advocate! - if rather than `int`s the members were custom classes that had to meet the definition of trivial (e.g. no non-default constructor), that would be a reason to assign in the body instead of constructing in the init list. however, the number of scenarios in which this is useful are, presumably, a tiny minority, so init lists should definitely be the default recommendation - with the rare exceptions being carefullly qualified and justified, unlike here. – underscore_d Dec 17 '15 at 21:51
  • 1
    @underscore_d No it wouldn't be such a reason. You can use initialiser lists in all cases except where member variables are interdependent, and that is a violation of 3NF ;-) – user207421 May 22 '16 at 02:40
  • @EJP It very much **can** be a reason; I've needed it several times. I think you're focussing on the parent initialisation, but I'm talking about its members. For member objects whose `default` ctors are inappropriate & standard layout precludes non-`default` constructors, one _must_ perform 'initialisation' another way, be it `operator=` or an init function or whatever. It makes sense to do this 'iniitialisation' in the parent's constructor i.e. assign in its body. `operator=` here is equivalent to in-body assignment of primitives as in the post. Overthinking or tangential maybe, but true ;-) – underscore_d May 22 '16 at 11:17
  • @jamesdlin, the first form is valuable for explicitly initializing an array exactly how you want it. Update...or is that possible in an initialization list too? – Gabriel Staples Dec 11 '19 at 21:37
  • 1
    @GabrielStaples If you're initializing individual elements of an array, then yes, you would need to do that in a constructor body. Obviously there are some things that *must* be done in a constructor body. My earlier comment was specifically talking about the specific examples in this answer. – jamesdlin Dec 11 '19 at 22:16
4

An explicit default initialization can help:

struct foo {
    bool a {};
    bool b {};
    bool c {};
 } bar;

Behavior bool a {} is same as bool b = bool(); and return false.

Anamnian
  • 417
  • 4
  • 20