When I use an initializer list to create a struct, but the initializer list contains fewer elements than my struct, I see the remaining elements are initialized with zeroes.
Is this an undefined behaviour and I'm seeing zeroes because my compiler (VS2015) decided to zero the memory for me?
Or could someone point me to the documentation that explains this behaviour in C++?
This is my code:
struct Thing {
int value;
int* ptr;
};
void main() {
Thing thing { 5 };
std::cout << thing.value << " " << thing.ptr << std::endl;
}
And this is what it prints:
5 00000000
That last element is the one that got zeroed without an initializer.
This is defined behaviour. According to the rule of aggregate initialization, the remaining member ptr will be value-initialized, i.e. zero-initialized to NULL pointer.
(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 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.
Related
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.
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{}.
Is the following legal?
class Aggregate {
public:
int a;
int b;
};
class Class {
public:
Class():
m_aggregate{
3,
// Here, m_aggregate.a is fully constructed, but m_aggregate is not
m_aggregate.a + 5
} {
}
Aggregate m_aggregate;
};
Is it legal to use elements of an aggregate after their lifetime has begun, but before the completion of the constructor of the aggregate as a whole?
Testing with gcc 4.8.2 seems to behave correctly...
I don't think that's legitimate. It is true that the elements of the braced list are initialized in order (i.e. the evaluation of list elements is sequenced, cf. 8.5.4/4), but the aggregate is only constructed after the list has been fully constructed. Cf. 8.5.1:
When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause.
In order to copy-initialize from something, the original needs to exist first.
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
Is this list-initialization of an array of unknown size valid in C++0x?
int main() { int x[]{0, 1,2,3,4}; return x[0]; }
I believe it is valid, but would appreciate some confirmation.
If anyone could quote from the C++0x-FCD to support their case, it would be greatly appreciated.
Thanks!
This goes from 8.5/16 first bullet to 8.5.4 list-initialization and from 8.5.4/3 third bullet to 8.5.1 aggregate initialization and then 8.5.1/4 says
An array of unknown size initialized with a brace-enclosed initializer-list containing n initializer-clauses, where shall be greater than zero, is defined as having elements
The only difference if the object is an array between = { ... } and { ... } is that the first is called copy-list-initialization and the second is called direct-list-initialization, so both are kinds of list-initialization. The elements of the array are copy-initialized from the elements of the initializer list in both cases.
Notice that there is a subtle difference between those forms if the array has a size and the list is empty, in which case 8.5.4 second bullet applies:
struct A {
explicit A();
};
A a[1]{}; // OK: explicit constructor can be used by direct initialization
A a[1] = {}; // ill-formed: copy initialization cannot use explicit constructor
This difference does not apply to lists that have content in which case third bullet applies again, though
struct A {
explicit A(int);
};
A a[1]{0}; // ill-formed: elements are copy initialized by 8.5.1
A a[1] = {0}; // ill-formed: same.
The FCD changed this compared to the previous draft, and initialization with an empty initializer list now always works even with explicit default constructors. This is because the FCD states that the elements are value-initialized, and value initialization doesn't care about explicitness since it doesn't do overload resolution on default constructors (it couldn't figure out better or worse matches anyway). The previous draft used normal overload resolution on the constructors and thus rejected explicit default constructors during copy initialization. This defect report did that change.
Yes, it is valid, and has been for decades, even in C. The size is simply set to the number of elements supplied. I don't know the reference, unfortunately.
(Added bonus...) If you need the number of elements use sizeof(x)/sizeof(*x). It's safer than hard-coding a constant that may become invalid if you add or remove entries.
EDIT: As pointed out in the comments, the code in question is missing an = (a fact that I missed), without which it isn't valid in any current standard of C or C++.