Что такое aggregate initialization

Initializers

An initializer specifies the initial value of a variable. You can initialize variables in these contexts:

In the definition of a variable:

As one of the parameters of a function:

As the return value of a function:

Initializers may take these forms:

An expression (or a comma-separated list of expressions) in parentheses:

An equals sign followed by an expression:

A braced initializer list. The list may be empty or may consist of a set of lists, as in the following example:

Kinds of initialization

There are several kinds of initialization, which may occur at different points in program execution. Different kinds of initialization are not mutually exclusive—for example, list initialization can trigger value initialization and in other circumstances, it can trigger aggregate initialization.

Zero initialization

Zero initialization is the setting of a variable to a zero value implicitly converted to the type:

Numeric variables are initialized to 0 (or 0.0, or 0.0000000000, etc.).

Arrays, POD classes, structs, and unions have their members initialized to a zero value.

Zero initialization is performed at different times:

At program startup, for all named variables that have static duration. These variables may later be initialized again.

During value initialization, for scalar types and POD class types that are initialized by using empty braces.

For arrays that have only a subset of their members initialized.

Here are some examples of zero initialization:

Default initialization

Default initialization for classes, structs, and unions is initialization with a default constructor. The default constructor can be called with no initialization expression or with the new keyword:

If the class, struct, or union does not have a default constructor, the compiler emits an error.

Scalar variables are default initialized when they are defined with no initialization expression. They have indeterminate values.

Arrays are default initialized when they are defined with no initialization expression. When an array is default-initialized, its members are default initialized and have indeterminate values, as in the following example:

If the array members do not have a default constructor, the compiler emits an error.

Default initialization of constant variables

Constant variables must be declared together with an initializer. If they are scalar types they cause a compiler error, and if they are class types that have a default constructor they cause a warning:

Default initialization of static variables

Static variables that are declared with no initializer are initialized to 0 (implicitly converted to the type).

For more information about initialization of global static objects, see main function and command-line arguments.

Value initialization

Value initialization occurs in the following cases:

a named value is initialized using empty brace initialization

an anonymous temporary object is initialized using empty parentheses or braces

an object is initialized with the new keyword plus empty parentheses or braces

Value initialization does the following:

for classes with at least one public constructor, the default constructor is called

for non-union classes with no declared constructors, the object is zero-initialized and the default constructor is called

for arrays, every element is value-initialized

in all other cases, the variable is zero initialized

Copy initialization

Copy initialization is the initialization of one object using a different object. It occurs in the following cases:

a variable is initialized using an equals sign

an argument is passed to a function

an object is returned from a function

an exception is thrown or caught

a non-static data member is initialized using an equals sign

class, struct, and union members are initialized by copy initialization during aggregate initialization. See Aggregate initialization for examples.

The following code shows several examples of copy initialization:

Copy initialization cannot invoke explicit constructors.

In some cases, if the copy constructor of the class is deleted or inaccessible, copy initialization causes a compiler error.

Direct initialization

Direct initialization is initialization using (non-empty) braces or parentheses. Unlike copy initialization, it can invoke explicit constructors. It occurs in the following cases:

a variable is initialized with non-empty braces or parentheses

a variable is initialized with the new keyword plus non-empty braces or parentheses

a variable is initialized with static_cast

in a constructor, base classes and non-static members are initialized with an initializer list

in the copy of a captured variable inside a lambda expression

The following code shows some examples of direct initialization:

List initialization

List initialization occurs when a variable is initialized using a braced initializer list. Braced initializer lists can be used in the following cases:

a variable is initialized

a class is initialized with the new keyword

an object is returned from a function

an argument passed to a function

one of the arguments in a direct initialization

in a non-static data member initializer

in a constructor initializer list

The following code shows some examples of list initialization:

Aggregate initialization

Aggregate initialization is a form of list initialization for arrays or class types (often structs or unions) that have:

no private or protected members

no user-provided constructors, except for explicitly defaulted or deleted constructors

no virtual member functions

In Visual Studio 2015 and earlier, an aggregate is not allowed to have brace-or-equal initializers for non-static members. This restriction was removed in the C++14 standard and implemented in Visual Studio 2017.

Aggregate initializers consist of a braced initialization list, with or without an equals sign, as in the following example:

You should see the following output:

Array members that are declared but not explicitly initialized during aggregate initialization are zero-initialized, as in myArr3 above.

Initializing unions and structs

If a union does not have a constructor, you can initialize it with a single value (or with another instance of a union). The value is used to initialize the first non-static field. This is different from struct initialization, in which the first value in the initializer is used to initialize the first field, the second to initialize the second field, and so on. Compare the initialization of unions and structs in the following example:

Initializing aggregates that contain aggregates

Aggregate types can contain other aggregate types, for example arrays of arrays, arrays of structs, and so on. These types are initialized by using nested sets of braces, for example:

Reference initialization

Variables of reference type must be initialized with an object of the type from which the reference type is derived, or with an object of a type that can be converted to the type from which the reference type is derived. For example:

The only way to initialize a reference with a temporary object is to initialize a constant temporary object. Once initialized, a reference-type variable always points to the same object; it cannot be modified to point to another object.

Although the syntax can be the same, initialization of reference-type variables and assignment to reference-type variables are semantically different. In the preceding example, the assignments that change iVar and lVar look similar to the initializations, but have different effects. The initialization specifies the object to which the reference-type variable points; the assignment assigns to the referred-to object through the reference.

Because both passing an argument of reference type to a function and returning a value of reference type from a function are initializations, the formal arguments to a function are initialized correctly, as are the references returned.

Reference-type variables can be declared without initializers only in the following:

Function declarations (prototypes). For example:

Function-return type declarations. For example:

Declaration of a reference-type class member. For example:

When initializing a reference-type variable, the compiler uses the decision graph shown in the following figure to select between creating a reference to an object or creating a temporary object to which the reference points.

Что такое aggregate initialization. Смотреть фото Что такое aggregate initialization. Смотреть картинку Что такое aggregate initialization. Картинка про Что такое aggregate initialization. Фото Что такое aggregate initialization
Decision graph for initialization of reference types

Initialization of external variables

Источник

what is aggregate initialization

The section «Array Initialization» in Chapter 4, page 231 of «Thinking in Java, 2nd Edition» has this to say:

Initializing arrays in C is error-prone and tedious. C++ uses aggregate initialization to make it much safer. Java has no “aggregates” like C++, since everything is an object in Java. It does have arrays, and these are supported with array initialization.

Why is it error prone and tedious in C? What does it mean by aggregate initialization and why is it safer? I came across the chapter «Aggregate initialization» in Bruce Eckel’s «Thinking in C++» (2nd Ed.), but it doesn’t convince me of anything.

Что такое aggregate initialization. Смотреть фото Что такое aggregate initialization. Смотреть картинку Что такое aggregate initialization. Картинка про Что такое aggregate initialization. Фото Что такое aggregate initialization

2 Answers 2

First of all, to answer the main question, aggregate initialization means the use of brace-enclosed initializer lists to initialize all members of an aggregate (i.e. an array or struct [in C++, only certain types of structs count as aggregates]).

because the latter gives ample opportunity for typos and other errors in the indices of the individual elements to be initialized.

Looking at today’s C and C++, it’s unclear to me why the author makes a distinction between C and C++. Both languages enable aggregate initialization for arrays.

One possibility is that the author referred to old versions of the C Standard. Notably, in ANSI C (C89) an important restriction applied to the use of aggregate initialization: All initializers had to be constant expressions:

This is due to 3.5.7 in C89 (quoting from the draft I found here):

All the expressions in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type shall be constant expressions.

This clearly limits the usefulness of aggregate initialization (and even in 1989, I believe many compilers implemented extensions to enable aggregate initialization also for non-constant expressions).

Later versions of the C Standard did not have this restriction, and the standardized versions of C++ (starting with C++98), I believe, never had any such restriction.

I can only speculate, but perhaps this is what the author had in mind?

I am assuming that the author is warning you about the lack of enforcing size constraints in C and C++. In C and C++, arrays decay down to pointers to their first element. It then uses pointer arithmetic to find the element you are refering to by index. Since arrays are not objects and the compiler makes no effort to store their size, there are no length checks. In java, arrays are objects and therefore their size is known. This size can be checked against, which safe guards the developer from accessing memory which doesn’t belong to him/her when overstepping the bounds of the array.

I find it strange the statement ‘C++ uses aggregate initialize to make it much safer’ was even used in this context.

Aggregate initialization, which is common to most modern languages, is as follows

This type of initialization assumes you know the size of the array beforehand and its contents. This type of initialization safe guards one from over stepping the boundary and provides for initializing an array with set values. Maybe in this case the author has in a mind a developer who declared a static C array of size 5. This developer then creates a loop to initialize its content but oversteps the boundary of the array by one, writing to memory that is not his/hers.

Источник

Aggregate initialization

Compiler support
Freestanding and hosted
Language
Standard library headers
Named requirements
Feature test macros (C++20)
Language support library
Concepts library (C++20)
Diagnostics library
General utilities library
Strings library
Containers library
Iterators library
Ranges library (C++20)
Algorithms library
Numerics library
Localizations library
Input/output library
Filesystem library (C++17)
Regular expressions library (C++11)
Atomic operations library (C++11)
Thread support library (C++11)
Technical specifications
Symbols index
External libraries
Initializer
Default initialization
Value initialization
Direct initialization
Copy initialization
List initialization (C++11)
Aggregate initialization
Reference initialization
Copy elision
Static initialization
Zero initialization
Constant initialization
Dynamic non-local initialization
Ordered dynamic initialization
Unordered dynamic initialization
Class member initialization
Member initializer list
Default member initializer (C++11)

Initializes an aggregate from braced-init-list.

Contents

[edit] Syntax

[edit] 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:

The effects of aggregate initialization are:

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 designator s used in the expression must appear in the same order as the data members of T.

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.

For a non-union aggregate, elements 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):

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

[edit] Character arrays

[edit] Notes

Until C++11, narrowing conversions were permitted in aggregate initialization, but they are no longer allowed, except that, as of C++20, narrowing conversions are allowed when aggregate initialization uses parentheses rather than braces.

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

Источник

aggregate initialization

Language
Standard Library Headers
Freestanding and hosted implementations
Named requirements
Language support library
Concepts library (C++20)
Diagnostics library
Utilities library
Strings library
Containers library
Iterators library
Ranges library (C++20)
Algorithms library
Numerics library
Input/output library
Localizations library
Regular expressions library (C++11)
Atomic operations library (C++11)
Thread support library (C++11)
Filesystem library (C++17)
Technical Specifications
Initializer
Default initialization
Value initialization
Direct initialization
Copy initialization
List initialization
Aggregate initialization
Reference initialization
Copy elision
Static initialization
Zero initialization
Constant initialization
Dynamic non-local initialization
Ordered dynamic initialization
Unordered dynamic initialization
Class member initialization
Member initializer list
In-class brace-or-equal initializer

Initializes an aggregate from braced-init-list

Syntax

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:

The effects of aggregate initialization are:

If the aggregate initialization uses copy- (until C++14) list-initialization syntax ( T a = < args.. >or T a < args.. >(since C++14) ), 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 members of T, and all designator s used in the expression must appear in the same order as the data members of T.

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.

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):

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

Character arrays

Notes

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

Источник

Инициализация агрегатных типов

Агрегатный тип — это тип структуры, объединения или массива. Если агрегатный тип содержит члены агрегатных типов, правила инициализации применяются рекурсивно.

Синтаксис

initializer:
<initializer-list> /* Для агрегатной инициализации */
<initializer-list, >

initializer-list:
initializer
initializer-list,initializer

Параметр initializer-list содержит список инициализаторов, разделенных запятыми. Каждый инициализатор в списке является константным выражением или списком инициализаторов. Поэтому списки инициализаторов могут быть вложенными. Эта форма полезна для инициализации агрегатных членов агрегатного типа, как показано в примерах этого раздела. Однако если инициализатор для автоматического идентификатора является одним выражением, оно не обязательно должно быть константным; достаточно, чтобы выражение имело соответствующий тип для назначения идентификатору.

В каждом списке инициализаторов значения константных выражений присваиваются соответствующим членам агрегатной переменной по порядку.

Если initializer-list имеет меньше значений, чем агрегатный тип, оставшиеся члены или элементы агрегатного типа инициализируются значением 0. Начальное значение автоматического идентификатора, которое не инициализировано явно, не определено. Если initializer-list имеет больше значений, чем агрегатный тип, выдается ошибка. Эти правила применяются к каждому внедренному списку инициализаторов, а также к агрегату в целом.

Инициализатор структуры является выражением того же типа или списком инициализаторов для членов, заключенных в фигурные скобки ( ). Безымянные члены битового поля не инициализируются.

При инициализации объединения параметр initializer-list должен быть одним константным выражением. Значение константного выражения присваивается первому члену объединения.

Если размер массива неизвестен, количество инициализаторов определяет размер массива, а его тип становится полным. Не существует способа указать повторение инициализатора в C или инициализировать элемент в середине массива без предоставления всех предыдущих значений. Если этот оператор требуется в программе, напишите подпрограмму на языке ассемблера.

Обратите внимание, что количество инициализаторов может задать размер массива.

Если указать размер и присвоить неверное количество инициализаторов, компилятор выдаст ошибку.

Блок, относящийся только к системам Microsoft

Максимальный размер массива определяется параметром size_t. Определенный в файле заголовка STDDEF.H параметр size_t представляет собой с диапазоном от 0x00000000 до 0x7CFFFFFF.

Завершение блока, относящегося только к системам Майкрософт

Примеры

В следующем примере представлены инициализаторы массива.

Этот оператор объявляет P как массив, состоящий из трех строк и четырех столбцов, и инициализирует элементы первой строки значением 1, элементы второй строки — значением 2 и т. д. до четвертой строки. Обратите внимание, что список инициализаторов для третьей и четвертой строк содержит запятые после последнего константного выражения. За последним списком инициализаторов ( <4, 4, 4,>, ) также следует запятая. Эти дополнительные запятые являются допустимыми, но не обязательными; обязательными являются только запятые, которые отделяют одно константное выражение от другого, и запятые, которые отделяют один список инициализаторов от другого.

Если агрегатный член не имеет встроенный список инициализаторов, значения присваиваются каждому члену подагрегата по порядку. Таким образом, инициализация в предыдущем примере эквивалентна следующему.

В фигурные скобки также можно заключать отдельные инициализаторы в списке, что могло бы пояснить пример выше.

При инициализации агрегатной переменной фигурные скобки и списки инициализаторов следует использовать с осторожностью. В следующем примере подробно показано то, как компилятор интерпретирует фигурные скобки.

В этом примере параметр nlist объявлен как массив структур, состоящий из двух строк и трех столбцов, где каждая структура имеет три члена. Строка 1 инициализации присваивает значения первой строке nlist следующим образом.

Первая открывающая фигурная скобка в строке 1 сообщает компилятору, что начинается инициализация первого агрегатного члена nlist (то есть nlist[0] ).

Вторая открывающая фигурная скобка указывает, что начинается инициализация первого агрегатного члена nlist[0] (то есть структуры nlist[0][0] ).

Строка 2 присваивает значения второй строке nlist аналогичным образом. Обратите внимание, что требуются внешние пары фигурных скобок, в которые будут заключены инициализаторы в строках 1 и 2. В следующей конструкции внешние фигурные скобки отсутствуют, и это привело бы к ошибке.

В следующем примере три члена int x инициализируются значениями 1, 2 и 3 соответственно.

В структуре list выше три элемента в первой строке m инициализируются значением 4,0; элементы оставшейся части строки m инициализируются значением 0,0 по умолчанию.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *