I'm using the clang compiler (c++ 11 I think) that comes with RAD studio 10.2. By mistake I discovered today that the first n members of a struct or array can be assigned using the usual curly brackets e.g.
int a[500]={1};
struct {int a,b,c;} st={2,3};
The above compiles and works fine but I've never come across this or seen it used before and I can find no mention of it online (maybe I'm searching using the wrong type of wording). Is this c++ documented?
For aggregate initialization,
(emphasis mine)
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) by 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).
That means, for int a[500]={1};, the 1st element is initialized to 1 and the remaining 499 elements of the array are value-initialized to 0. For struct {int a,b,c;} st={2,3};, the member a is initialized to 2 and b is initialized to 3, the last member c is value-initialized to 0 too.
I've never come across this or seen it used before and I can find no mention of it online (maybe I'm searching using the wrong type of wording). Is this c++ documented?
Yes, this is documented. This syntax is called list initialisation - and more specifically since the types are aggregates: This is aggregate initialisation.
Initialise first n members only of struct or array
It is not possible to only initialise some members / elements. If you list initialise class object or array, then all of it will be initialised. The members / elements which lack an initialiser will be value initialised.
If you wanted to do that, then what you can do instead is default initialise the class object or array, and then initialise the sub objects selectively afterwards.
Related
These two lines from cppreference
What is the difference between these two statements ? I don't see any difference
until c++14
If the braced-init-list is empty and T is a class type with a default
constructor, value-initialization is performed. Otherwise, if T is an
aggregate type, aggregate initialization is performed.
since c++14
If T is an aggregate type, aggregate initialization is performed.
Otherwise, if the braced-init-list is empty and T is a class type with
a default constructor, value-initialization is performed.
The difference is which one happens when both conditions apply: if T is an aggregate class (as opposed to an array), which certainly has a default constructor, and the braced-init-list is empty. Of course, to understand why that matters, we then have to distinguish value initialization from aggregate initialization from an empty list.
Value initialization zero-initializes the object and then default-initializes it, which for an aggregate is default-initializing each of its members, so the value-initialization is member-wise (plus zeroing padding). Aggregate initialization initializes each member from {}, which is again value initialization for many types but is default initialization for members of class type with a user-provided default constructor. The difference can be seen in
struct A {A() {} int i;};
struct B {A a;}; // aggregate
B b{}; // i is 0 in C++11, uninitialized in C++14
B b2=B(); // i is 0 in both versions
In C++14 only, aggregates can have default member initializers; that can't contribute to a difference in behavior between the two language versions, of course, but it doesn't behave differently between these two rules anyway (since it replaces only the common default initialization).
The difference is the sequence of checking, so the aggregate type checking is taking place at the first place, and only then the rest.
I came upon this interesting answer when our team was dealing with a valgrind warning about unitialized members of a POD in our C++ code:
https://stackoverflow.com/a/5914697/629530
Restating the salient points, consider the following POD structure in C++:
struct C
{
int x;
int y;
};
The following invocations of constructing an object of type C invokes the default constructor and the members are initialized with that default constructor (again, copying the code and comments from Martin York's answer):
C c = C(); // Zero initialize using default constructor
C c{}; // Latest versions accept this syntax.
C* c = new C(); // Zero initialize a dynamically allocated object.
Makes sense. Martin York goes on to point out that the with the following declarations, however, the members of c are not initialized via a constructor and therefore contain undefined data:
C c; // members are random
C* c = new C; // members are random (more officially undefined).
That's interesting. I had used braced-init-list initialization of POD types before, but I didn't realize that C c; would not call the default constructor for a POD type. His answer satisfies the question, but I'd like to know specifically what is instantiated when the latter, non-default constructed c objects are declared. Specifically, the following would be helpful to me:
What is the official name for this non-default initialization of POD types? I'm having trouble googling for this mechanism because I don't know its name.
If the POD type has something less trivial than an int-type, such as a std::string, is the memory for that member also initialized with undefined values? Or is the default constructor for a std::string called for that member?
Update.
Thanks for the input. This has been duplicated to a question with this single answer:
https://stackoverflow.com/a/8860787/629530
According to that answer (and the answers to the question it is duplicated to), a declaration of the form without a parentheses is called "default initialized":
Info *p = new Info; <------- Default Initialization
For default initialization, these points about initialization are made:
To default-initialize an object of type T means:
if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is an array type, each element is default-initialized;
otherwise, the object is zero-initialized.
I might be misunderstanding something, but the struct named C proposed above is a POD type that is not an array. Thus it should be zero initialized? The members are not, however, zero initialized but contain undefined values. How do I reconcile this?
default-initialize an object of type T means:
... otherwise, the object is zero-initialized.
No.
Your first linked answer is correct about C++11 onwards, and this is called default-initialization. It's different to default-construction or value initialization.
The second linked answer was probably correct for C++03, but is wrong for C++11 onwards (even though it was written in 2012). I don't have a copy of the '03 standard to verify, and it was a long time ago.
The effects of default initialization are:
if T is a non-POD (until C++11) class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;
if T is an array type, every element of the array is default-initialized;
otherwise, nothing is done: the objects with automatic storage duration (and their subobjects) are initialized to indeterminate values.
Local copy of N4659 agrees with the summary above:
11.6 Initializers [dcl.init]
...
(7.3) Otherwise, no initialization is performed
The section on new-expressions even refers to 11.6 and then says
Note: If no initialization is performed, the object has an indeterminate value.— end note
Current draft has
9.3 Initializers [dcl.init]
...
(7.3) Otherwise, no initialization is performed.
This questions received too little attention in forums.
It has been asked before but no one captured this little detail. As a result I am not sure if I am doing the right thing:
Simple example:
struct TEST {
bool a;
int b;
};
TEST func() {
return { false };
}
Is this correct? Note that int value is not initialized.
While it would not be a problem to just set it to 0, more problems arise:
struct _FILE_MUTEX {
bool locked;
HANDLE handle;
};
And the last member of the structure could become more and more complex from vector,arrays to function pointers.
Can I leave some of the members empty when returning an inline-initialised structure?
This is called aggregate initialization.
https://en.cppreference.com/w/cpp/language/aggregate_initialization
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) by 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.
Thus, in aggregate initialization you allowed to provide less clauses than members in structure. Every remaining member (e.g. X), that doesn't have default initializer, would be initialized as X{}.
Let's say I have a class with a member array of std::atomics, where the
array is sized via a computation (i.e. it may change based on other constants elsewhere in the program):
class Foo {
static constexpr size_t kArraySize = ComputeArraySize();
std::atomic<size_t> atomics_[kArraySize];
};
What is the most elegant way to ensure that the atomics are all initialized to
zero? Can I do better than looping over the array in Foo's constructor and
explicitly storing zero? Does the answer differ for std::array?
Normally I would use a brace initializer here, but the derived length (which
may be long) makes it difficult.
Note that I cannot assume that the instance of Foo has static storage
duration.
Okay, I believe I've worked this through. Both of these will initialize all of
the atomics to zero:
std::atomic<size_t> plain_array[kArraySize] = {};
std::array<std::atomic<size_t>, kArraySize> std_array = {};
Here's the logic:
[dcl.init.aggr]/1 defines arrays to be aggregates.
[array.cons]/1 mandates that std::array also be an aggregate.
[dcl.init.aggr]/7 says that if there are fewer elements of the initializer
list than there are members in the aggregate, then the remaining members
shall be initialized from an empty initializer list. In this case, that's
all members.
[dcl.init.list]/3 defines list-initialization from an empty list for a class
with a default constructor (as with std::atomic) to cause
value-initialization.
[dcl.init]/7 says that classes without user-provided constructors are
zero-initialized. Assuming that std::array<T> contains an array of T,
and that the zero representation of std::atomic<size_t> is what we expect,
then we're good.
Now, std::atomic does have a user-provided constructor, just not a
user-provided default constructor (the latter is explicitly defaulted). So
it doesn't technically fit the conditions of the last point. But it seems this
is an error in the standard, and has been fixed in more recent
drafts.
For example, if somestruct has three integer members, I had always thought that it was OK to do this in C (or C++) function:
somestruct s = {123,};
The first member would be initialized to 123 and the last two would be initialized to 0. I often do the same thing with automatic arrays, writing int arr[100] = {0,}; so that all integers in an array are initialized to zero.
Recently I read in the GNU C Reference Manual that:
If you do not initialize a structure variable, the effect depends on
whether it is has static storage (see Storage Class Specifiers) or
not. If it is, members with integral types are initialized with 0 and
pointer members are initialized to NULL; otherwise, the value of the
structure's members is indeterminate.
Can someone please tell me what the C and C++ standards say regarding partial automatic structure and automatic array initialization? I do the above code in Visual Studio without a problem but I want to be compatible with gcc/g++, and maybe other compilers as well. Thanks
The linked gcc documentation does not talk of Partial Initialization it just talks of (Complete)Initialization or No Initialization.
What is partial Initialization?
The standards do not define Partial initialization of objects, either there is Complete initialization or No-initialization. Partial Initialization is a non-standard terminology which commonly refers a situation where you provide some initializers but not all i.e: Fewer initializers than the size of the array or the number of structure elements being initialized.
Example:
int array[10] = {1,2}; //Case 1:Partial Initialization
What is (Complete)Initialization or No Initialization?
Initialization means providing some initial value to the variable being created at the same time when it is being created. ie: in the same code statement.
Example:
int array[10] = {0,1,2,3,4,5,6,7,8,9}; //Case 2:Complete Initialization
int array[10]; //Case 3:No Initialization
The quoted paragraph describes the behavior for Case 3.
The rules regarding Partial Initialization(Case 1) are well defined by the standard and these rules do not depend on the storage type of the variable being initialized.
AFAIK, All mainstream compilers have 100% compliance to these rules.
Can someone please tell me what the C and C++ standards say regarding partial automatic structure and automatic array initialization?
The C and C++ standards guarantee that even if an integer array is located on automatic storage and if there are fewer initializers in a brace-enclosed list then the uninitialized elements must be initialized to 0.
C99 Standard 6.7.8.21
If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
In C++ the rules are stated with a little difference.
C++03 Standard 8.5.1 Aggregates
Para 7:
If there are fewer initializers in the list than there are members in the aggregate, then each member not explicitly initialized shall be value-initialized (8.5).
[Example:
struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };
initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form int(), that is,0. ]
While Value Initialization is defined in,
C++03 8.5 Initializers
Para 5:
To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible
default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static
data member and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized
In C, objects are never partially initialised - if any part of them is initialised, the entire object (and all sub-objects recursively) are initialised. If no explicit initialiser is provided then elements are initialised to "zero of the appropriate type".
The quote in your question is referring to when the initialiser for the entire object is completely left out, not when a sub-object lacks an initialiser. For example, assuming that arr has automatic storage duration, then this:
int arr[100] = { 123 };
initialises arr[0] to 123 and every other element of arr to 0. Whereas this:
int arr[100];
leaves every element of arr uninitialised. It is this latter case that the quote is in reference to.
newest gcc versions also allow to "partially" initialize and zeromem at the same time:
typedef struct{
int a,b,c;
}T;
T s = {0, .b=5};
the struct members now will have these values: a=0, b=5, c=0
i don't have any info on whether other compilers allow this or not :p