Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/language/aggregate initialization"

From cppreference.com
< cpp‎ | language
m (Example: CWG 1207)
m (Example: typo: CWG 1270)
Line 144: Line 144:
 
     S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision
 
     S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision
 
     S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax
 
     S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax
     S s4{1, 2, 3, 4, 5, 6}; // error until CWG 1207:  
+
     S s4{1, 2, 3, 4, 5, 6}; // error until CWG 1270:  
 
                             // brace elision only allowed with equals sign
 
                             // brace elision only allowed with equals sign
  

Revision as of 18:56, 23 December 2020

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

Initializes an aggregate from braced-init-list.

Contents

Syntax

T object = {arg1, arg2, ...}; (1)
T object {arg1, arg2, ... }; (2) (since C++11)
T object = { .designator = arg1 , .designator { arg2 } ... }; (3) (since C++20)
T object { .designator = arg1 , .designator { arg2 } ... }; (4) (since C++20)
T object (arg1, arg2, ...); (5) (since C++20)

Explanation

Aggregate initialization initializes aggregates. It is a form of list-initialization(since C++11) or direct initialization(since C++20)

An aggregate is one of the following types:

  • array type
  • class type (typically, struct or union), that has
  • no private or protected direct (since C++17)non-static data members
  • no user-declared constructors
(until C++11)
  • no user-provided constructors (explicitly defaulted or deleted constructors are allowed)
(since C++11)
(until C++17)
  • no user-provided, inherited, or explicit constructors (explicitly defaulted or deleted constructors are allowed)
(since C++17)
(until C++20)
  • no user-declared or inherited constructors
(since C++20)
  • no virtual, private, or protected(since C++17) base classes
  • no virtual member functions
(since C++11)
(until C++14)

The effects of aggregate initialization are:

  • Each direct public base,(since C++17) array element, or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.
  • If the initializer clause is an expression, implicit conversions are allowed as per copy-initialization, except, for list-initialization form, narrowing conversions are prohibited(since C++11).
  • If the initializer clause is a nested braced-init-list (which is not an expression), the corresponding array element/class member/public base(since C++17) is list-initialized from that clause: aggregate initialization is recursive.
  • If the object is an array of unknown size, and the supplied brace-enclosed initializer list has n clauses, the size of the array is n. (Note that the object in this case cannot be a non-static data member: a member must have complete type.)
  • Static data members and unnamed bit-fields are skipped during aggregate initialization.
  • If the number of initializer clauses exceeds the number of members and bases(since C++17) to initialize, the program is ill-formed.
  • If the number of initializer clauses is less than the number of members or initializer list is completely empty, the remaining members are value-initialized. If a member of a reference type is one of these remaining members, the program is ill-formed.
(until C++11)
  • If the number of initializer clauses is less than the number of members and bases(since C++17) or initializer list is completely empty, the remaining members and bases(since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise(since C++14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
(since C++11)
  • When a union is initialized by aggregate initialization, only its first non-static data member is initialized.

The braces around the nested initializer lists may be elided (omitted), in which case as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, and the subsequent initializer clauses are used to initialize the following members of the object. 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 empty nested list {} must be used.

Designated initializers

The syntax forms (3,4) are known as designated initializers: each designator must name a direct non-static data member of T, and all designators used in the expression must appear in the same order as the data members of T.

struct A { int x; int y; int z; };
A a{.y = 2, .x = 1}; // error; designator order does not match declaration order
A b{.x = 1, .z = 2}; // ok, b.y initialized to 0

Each direct non-static data member named by the designated initializer is initialized from the corresponding brace-or-equals initializer that follows the designator. Narrowing conversions are prohibited.

Designated initializer can be used to initialize a union into the state other than the first. Only one initializer may be provided for a union.

union u { int a; const char* b; };
u f = { .b = "asdf" };         // OK, active member of the union is b
u g = { .a = 1, .b = "asdf" }; // Error, only one initializer may be provided

For a non-union aggregate, element for which a designated initializer is not provided are initialized the same as described above for when the number of initializer clauses is less than the number of members (default member initializers where provided, empty list-initialization otherwise):

struct A {
  string str;
  int n = 42;
  int m = -1;
};
A{.m=21}  // Initializes str with {}, which calls the default constructor
          // then initializes n with = 42
          // then initializes m with = 21

If the aggregate that is initialized with a designated initializer clause has an anonymous union member, the corresponding designated initializer must name one of the members of that anonymous union.

Note: out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the C programming language, but are not allowed in C++.

struct A { int x, y; };
struct B { struct A a; };
struct A a = {.y = 1, .x = 2}; // valid C, invalid C++ (out of order)
int arr[3] = {[1] = 5};        // valid C, invalid C++ (array)
struct B b = {.a.x = 0};       // valid C, invalid C++ (nested)
struct A a = {.x = 1, 2};      // valid C, invalid C++ (mixed)
(since C++20)

Character arrays

Arrays of ordinary character types (char, signed char, unsigned char), char8_t(since C++20), char16_t, char32_t(since C++11), or wchar_t can be initialized from ordinary string literals, UTF-8 string literals(since C++20), UTF-16 string literals, UTF-32 string literals(since C++11), or wide string literals, respectively, 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.

char a[] = "abc";
// equivalent to char a[4] = {'a', 'b', 'c', '\0'};
 
//  unsigned char b[3] = "abc"; // Error: initializer string too long
unsigned char b[5]{"abc"};
// equivalent to unsigned char b[5] = {'a', 'b', 'c', '\0', '\0'};
 
wchar_t c[] = {L"кошка"}; // optional braces
// equivalent to wchar_t c[6] = {L'к', L'о', L'ш', L'к', L'а', L'\0'};

Notes

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, except that, as of C++20, they are allowed when aggregate initialization uses round parentheses.

Until C++11, aggregate initialization could only be used in variable definition, and could not be used in a constructor initializer list, a new-expression, or temporary object creation due to syntax restrictions.

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++.

Example

#include <string>
#include <array>
struct S {
    int x;
    struct Foo {
        int i;
        int j;
        int a[3];
    } b;
};
 
union U {
    int a;
    const char* b;
};
 
int main()
{
    S s1 = { 1, { 2, 3, {4, 5, 6} } };
    S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision
    S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax
    S s4{1, 2, 3, 4, 5, 6}; // error until CWG 1270: 
                            // brace elision only allowed with equals sign
 
    int ar[] = {1,2,3}; // ar is int[3]
    int ab[] (1, 2, 3); // (C++20) ab is int[3] 
//  char cr[3] = {'a', 'b', 'c', 'd'}; // too many initializer clauses
    char cr[3] = {'a'}; // array initialized as {'a', '\0', '\0'}
 
    int ar2d1[2][2] = {{1, 2}, {3, 4}}; // fully-braced 2D array: {1, 2}
                                        //                        {3, 4}
    int ar2d2[2][2] = {1, 2, 3, 4}; // brace elision: {1, 2}
                                    //                {3, 4}
    int ar2d3[2][2] = {{1}, {2}};   // only first column: {1, 0}
                                    //                    {2, 0}
 
    std::array<int, 3> std_ar2{ {1,2,3} };    // std::array is an aggregate
    std::array<int, 3> std_ar1 = {1, 2, 3}; // brace-elision okay
 
    int ai[] = { 1, 2.0 }; // narrowing conversion from double to int:
                           // error in C++11, okay in C++03
 
    std::string ars[] = {std::string("one"), // copy-initialization
                         "two",              // conversion, then copy-initialization
                         {'t', 'h', 'r', 'e', 'e'} }; // list-initialization
 
    U u1 = {1}; // OK, first member of the union
//    U u2 = { 0, "asdf" }; // error: too many initializers for union
//    U u3 = { "asdf" }; // error: invalid conversion to int
 
}
 
// aggregate
struct base1 { int b1, b2 = 42; };
// non-aggregate
struct base2 {
  base2() : b3(42) {}
  int b3;
};
// aggregate in C++17
struct derived : base1, base2 { int d; };
derived d1{ {1, 2}, { }, 4}; // d1.b1 = 1, d1.b2 = 2,  d1.b3 = 42, d1.d = 4
derived d2{ {    }, { }, 4}; // d2.b1 = 0, d2.b2 = 42, d2.b3 = 42, d2.d = 4

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 1270 C++11 brace elision was only allowed to be used in copy-list-initialization allowed elsewhere

See also

C documentation for Struct and union initialization