cppreference.com

Struct and union initialization.

When initializing an object of struct or union type, the initializer must be a non-empty, (until C23) brace-enclosed, comma-separated list of initializers for the members:

where the designator is a sequence (whitespace-separated or adjacent) of individual member designators of the form . member and array designators of the form [ index ] .

All members that are not initialized explicitly are empty-initialized .

[ edit ] Explanation

When initializing a union , the initializer list must have only one member, which initializes the first member of the union unless a designated initializer is used (since C99) .

When initializing a struct , the first initializer in the list initializes the first declared member (unless a designator is specified) (since C99) , and all subsequent initializers without designators (since C99) initialize the struct members declared after the one initialized by the previous expression.

It's an error to provide more initializers than members.

[ edit ] Nested initialization

If the members of the struct or union are arrays, structs, or unions, the corresponding initializers in the brace-enclosed list of initializers are any initializers that are valid for those members, except that their braces may be omitted as follows:

If the nested initializer begins with an opening brace, the entire nested initializer up to its closing brace initializes the corresponding member object. Each left opening brace establishes a new current object . The members of the current object are initialized in their natural order , unless designators are used (since C99) : array elements in subscript order, struct members in declaration order, only the first declared member of any union. The subobjects within the current object that are not explicitly initialized by the closing brace are empty-initialized .

If the nested initializer does not begin with an opening brace, only enough initializers from the list are taken to account for the elements or members of the member array, struct or union; any remaining initializers are left to initialize the next struct member:

[ edit ] Notes

The initializer list may have a trailing comma, which is ignored.

[ edit ] Example

Possible output:

[ edit ] References

[ edit ] See also

Powered by MediaWiki

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Brace initialization

It isn't always necessary to define a constructor for a class , especially ones that are relatively simple. Users can initialize objects of a class or struct by using uniform initialization, as shown in the following example:

When a class or struct has no constructor, you provide the list elements in the order that the members are declared in the class . If the class has a constructor, provide the elements in the order of the parameters. If a type has a default constructor, either implicitly or explicitly declared, you can use brace initialization with empty braces to invoke it. For example, the following class may be initialized by using both empty and non-empty brace initialization:

If a class has non-default constructors, the order in which class members appear in the brace initializer is the order in which the corresponding parameters appear in the constructor, not the order in which the members are declared (as with class_a in the previous example). Otherwise, if the type has no declared constructor, member initializers must appear in the brace initializer in the same order as they're declared. In this case, you can initialize as many of the public members as you wish, but you can't skip any member. The following example shows the order that's used in brace initialization when there's no declared constructor:

If the default constructor is explicitly declared but marked as deleted, empty brace initialization can't be used:

You can use brace initialization anywhere you would typically do initialization—for example, as a function parameter or a return value, or with the new keyword:

In /std:c++17 mode and later, the rules for empty brace initialization are slightly more restrictive. See Derived constructors and extended aggregate initialization .

initializer_list constructors

The initializer_list Class represents a list of objects of a specified type that can be used in a constructor, and in other contexts. You can construct an initializer_list by using brace initialization:

To use this class, you must include the <initializer_list> header.

An initializer_list can be copied. In this case, the members of the new list are references to the members of the original list:

The standard library container classes, and also string , wstring , and regex , have initializer_list constructors. The following examples show how to do brace initialization with these constructors:

Classes and Structs Constructors

Submit and view feedback for

Additional resources

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Brace (aggregate) initialization for structs with default values

Initializing a struct with default values is trivial:

and initializing a struct with a brace initializer is trivial too:

Suprisingly the init code won't compile, until I remove the default value. So, how would I do the init in such a case? I'd like to keep X a POD without c-tor.

Mike Lischke's user avatar

Here is some documentation relevant to the problem:

http://en.cppreference.com/w/cpp/language/aggregate_initialization

In c++11 your code is invalid. In c++14 it is valid again.

In C++11 adding a default initialization prevents braced init from being valid. In C++14, it does not.

A way to solve your problem in C++11 would be to write a constructor with the value for a and the b value with a default.

Yakk - Adam Nevraumont's user avatar

Your Answer

Sign up or log in, post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service , privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged c++ c++11 or ask your own question .

Hot Network Questions

struct brace initialization

Your privacy

By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy .

10.6 — Struct aggregate initialization

struct brace initialization

Brace initialization of user-defined types

Uniform initialization syntax is one of my favourite features of Modern C++.  I think it’s important, in good quality code, to clearly distinguish between initialization and assignment.

When it comes to user-defined types – structures and classes – brace initialization can throw up a few unexpected issues, and some counter-intuitive results (and errors!).

In this article, I want to have a look at some of the issues with brace initialization of user-defined types – specifically, brace elision and initializer_lists.

Read on for more…

User-defined types

We all know the hoary old interview question: “What’s the difference between structs and classes in C++”.  And we all regurgitate the same answer:

For Modern C++ there is also a third difference: the way brace initialization is handled.

For a structure, brace initialization performs a direct initialization of its members

For class types, brace initialization results in a call to a constructor.

There’s nothing to stop you adding a constructor to a struct. If you do, the braced initialization list becomes a call to a constructor.

There are some odd corner cases, that might throw you:

Even though we’ve explicitly deleted the two constructors, this code compiles just fine. The reason this works (maybe against your expectations) is that both objects are being direct initialized – that is, the constructors are not being called. The compiler can do this as the attributes are declared as public.

I can ‘break’ this code by actually defining one (or both) of the constructors explicitly

The compiler treats user-defined types with only public attributes as an aggregate type. It will attempt to direct initialize the members unless an appropriate constructor is defined. By extension, if I declare any private attributes aggregate initialization can no longer be applied (you can’t access the private member to initialize it); therefore, the braced initialization list must be used to call a constructor.

Brace elision

Brace elision is a syntactic mechanism to simplify (in some cases) nested structures.

If an aggregate type has a sub-aggregate (that is, another structure) element then the braces around the initializer of the sub-aggregate type may be omitted (elided). The compiler will take as many initializers from the list as required to initialize the element; the remaining iniitializers are then used to initialize any remaining members.

The first two initializations are pretty straightforward.  But let’s explore the second two initializations in a bit more detail. The initialization of inner3 is explicit and complete. We could view it like this

The initialization for inner4 uses brace elision. Instead of finding an opening brace for the initialization of Inner::arr , the compiler finds an expression. It assumes that this is meant to be the initialization list for the first (declared) member of Inner . It will then keep consuming initialization-expressions until the member is completely initialized, or it reaches a closing brace.

If we supply too many values, we get an error

In this example, if we supply too few initializers, the remainder of Inner::arr will be value initialized

The question that typically comes up is: why do we have this mechanism? The best answer I can give is std::array .

The STL array class is a thin wrapper around a C-style array. Basically, it’s a struct with a nested C-style array inside. A (highly simplified) implementation could look something like this:

To initialize a std::arra y with values you would have to provide two sets of braces – one set for the std::array , one set for the (nested) C-style array.

This looks awkward; and doesn’t fit in with the initialization syntax of anything else in the language. Brace elision makes our code look more ‘normal’

(If you’re using Clang it will emit a diagnostic about brace-elided initialization for std::array s)

Let’s now look at some corner cases where brace-elision may lead to code “not meeting developer expectations”.

Now we have a structure-within-a-structure.

The first three initializations should be pretty straightforward, based on what we’ve just talked about.

I’ll expand out the initialization of outer4 , as in the previous examples

(Note: The temporary Inner object will be constructed directly into the outer4 member; there will be no copying.)

The initialization for the object outer5 is similar, but this time we are eliding the braces around the temporary Inner object’s arr member.

Using copy initialization seems unnecessary at first glance but is actually a very useful convenience, particularly with class types as we’ll explore later.

For outer6 we have elided all the braces on internal members.

Let’s go all-in on this.  This time we have a structure that consists of an array of other structures (replace Outer with std::array to see where this is going…)

The horrible thing about this example is the code that looks it should work, doesn’t; and the code that looks like it shouldn’t work, does!

This is brace elision messing with us. Let’s expand these two examples to see why they work (or fail!) the way they do.

In the second example, by aligning the initializer braces it is easier to see where the problem lies. Brace elision of a member means that the compiler takes initializer values from the supplied braced initializer list. Here, we can see only two values are supplied for Inner::arr; therefore, the second pair of values are value-initialized.

To avoid this confusion you have to make sure you specify all the braces (that is, no brace elision)

If our nested type is a class then we are no longer direct-initializing the object(s) – we are calling constructors.

Given the following code

Our first two definitions give no problems (providing our ADT class supports default construction)

The following declarations give us similar issues to our previous examples.

As before, let’s expand these out and look for the brace elision (or not)

Using copy initialization makes the code a lot more comprehensible.

Technically, there is brace elision going on here; and we should really write

However, hopefully you will agree this actually detracts from the readability of the code.

List initialization of class types

Since one of the design goals of C++ was to emulate the behaviour of built-in types it seems reasonable that you should be able to initialise user-defined aggregate types (containers, etc.) in the same way.

Since the Track class has private data members, using brace initialization results in an attempted call to a constructor. In this case there is no constructor that takes four Position objects.

A std::initializer_list allows a class to be initialized with a list of arguments (although they must be of the same type).

When the compiler creates an initializer list the elements of the list are constructed on the stack (or in static memory, depending on the scope of the initializer list) as const objects. The compiler then creates the initializer_list object that holds the address of the first element and one-past-the-end of the last element. Note that the initializer_list object is very small (two pointers) so can be passed by copy; although you could pass by reference-to-const and save one pointer (at the cost of double-indirect access to the initialiser objects)

struct brace initialization

A brief look at the implementation of std::initializer_lis t can be enlightening as to its implementation. Here is a (simplified, for clarity) implementation.

The initializer_list object is an instance of a template class that consists of two pointers – one to the first element; and one pointing to one-past-the-end. (Alternatively, an initializer_lis t can be implemented as a pointer plus a length; the results are the same) A simple interface allows client code to access the elements using the Iterator pattern (as with other container-like entities).

The initializer list (and its list of initializing objects) is an r-value expression. Therefore, you must copy from the initializer list into your internal container.

Beware of potential confusion when overloading constructors with std::initializer_list. Given the following class

Different initialization declarations will yield different (and maybe unexpected!) results

The rules are as follows:

I’ll leave you with some of our guidelines regarding initialization in C++

Glennan Carnie

' src=

Glennan Carnie

Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry.

He specialises in C++, UML, software modelling, Systems Engineering and process development.

' src=

About Glennan Carnie

1 response to brace initialization of user-defined types.

' src=

Thanks for the thorough article!

Leave a Reply Cancel reply

aggregate initialization

Initializes an aggregate from braced-init-list

Explanation

Aggregate initialization is a form of list-initialization , which initializes aggregates

An aggregate is one of the following types:

The effects of aggregate initialization are:

Character arrays

Arrays of character types ( char , signed char , unsigned char , char16_t , char32_t , wchar_t ) can be initialized from an appropriate string literal , optionally enclosed in braces. Successive characters of the string literal (which includes the implicit terminating null character) initialize the elements of the array. If the size of the array is specified and it is larger than the number of characters in the string literal, the remaining characters are zero-initialized.

An aggregate class or array may include non-aggregate public bases (since C++17) , members, or elements, which are initialized as described above (e.g. copy-initialization from the corresponding initializer clause)

Until C++11, narrowing conversions were permitted in aggregate initialization, but they are no longer allowed.

Until C++11, aggregate initialization could not be used in a constructor initializer list due to syntax restrictions.

Until C++14, the direct-initialization form T a { args.. } did not permit brace elision.

In C, character array of size one less than the size of the string literal may be initialized from a string literal; the resulting array is not null-terminated. This is not allowed in C++.

DevOps Engineering - Planning to Production

Related Articles

Uniform Initialization in C++

Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values. The syntax is as follows:

Following are some of the examples of the different ways of initializing different types:

If initialized using brace initialization, the above code can be re-written as: 

  Applications of Uniform Initialization

Initialization of dynamically allocated arrays : 

Time Complexity: O(1) Auxiliary Space: O(1)  

Initialization of an array data member of a class :

Implicitly initialize objects to return : 

Time Complexity: O(1) Auxiliary Space: O(1)

Implicitly initialize function parameter  

Please Login to comment...

Master C++ Programming - Complete Beginner to Advanced

Complete interview preparation - self paced, full stack development with react & node js - live, improve your coding skills with practice, start your coding journey now.

IMAGES

  1. FS:: Jcw struct brace

    struct brace initialization

  2. Brace initialization of user-defined types : cpp

    struct brace initialization

  3. C# Struct: Definition, Examples, Best Practices, and Pitfalls

    struct brace initialization

  4. Double Brace Initialization in Java! Java Initialization technique

    struct brace initialization

  5. Double Brace Initialization in Java for List Collection Example

    struct brace initialization

  6. c ++ initialization of struct

    struct brace initialization

VIDEO

  1. LeetCode 1087. Brace Expansion

  2. Baltimore Style Dancing (Exclusive)

  3. Class vs Struct

  4. variable and types of variable in Java Amharic በአማርኛ

  5. 7.3 C++ struct initialization

  6. Fix Vulkan Initialization Failure in No Man’s Sky/Yuzu/Doom on Windows

COMMENTS

  1. Aggregate initialization

    The braces around the nested initializer lists may be elided (omitted), in which case as many initializer clauses as necessary are used to

  2. Struct and union initialization

    When initializing an object of struct or union type, the initializer must be a non-empty, (until C23) brace-enclosed, comma-separated list of

  3. Brace initialization for classes, structs, and unions

    Use brace initialization with any C++ class, struct, or union.

  4. Brace (aggregate) initialization for structs with default values

    and initializing a struct with a brace initializer is trivial too: X x = {1, 3};. Suprisingly the init code won't compile, until I remove the

  5. 10.6

    Aggregates use a form of initialization called aggregate initialization, which allows us to directly initialize the members of aggregates. To do

  6. Initialization of structures and unions

    An initializer for a structure is a brace-enclosed comma-separated list of values, and for a union, a brace-enclosed single value.

  7. Brace initialization of user-defined types

    Brace elision is a syntactic mechanism to simplify (in some cases) nested structures. If an aggregate type has a sub-aggregate (that is, another

  8. Understanding uniform initialization

    Brace-initialization is a uniform method for initializing data in C++11. For this reason, it is also called uniform initialization.

  9. aggregate initialization

    However, if the object has a sub-aggregate without any members (an empty struct, or a struct holding only static members), brace elision is not allowed, and an

  10. Uniform Initialization in C++

    In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values. The syntax is as follows: