The following example is from Stroustrup C++ 4th Ed. Page 519. It was my understanding from K&R C and earlier in the Stroustrup book that local automatic variables of primitive types are undefined or not known to be initialized. Static variables of primitive types or automatic variables of a class with a default constructor are initialized.
That would mean int b should be undefined and not known to be initialized. Yet, Stroustrup adds the following code comment saying b = 0. Is this Errata? Or perhaps some behavior of calling with the default constructor?
Thank you
struct S {
string a;
int b;
};
void f(void) {
S s0 {}; // default construction: {"",0}
// ...
}
It's easy. You can leave the built-in type variables uninitialized or you can ask the compiler to zero-initialize them.
S s1; // string is default initialized, int is left uninitialized
S s2{}; // All fields are initialized.
Notice the {}. That (in this case) asks the compiler to initialize all fields.
In this line:
S s0 {};
the syntax that is used is value-initialization, in particular
when a named variable (automatic, static, or thread-local) is declared with the initializer consisting of a pair of braces.
In this case, the effect of value-initialization is that the object s0 is zero-initialized.
In this particular case, the effect is:
If T is an non-union class type, all base classes and non-static data members are zero-initialized, and all padding is initialized to zero bits. The constructors, if any, are ignored.
which implies that the int member b is zero-initialized to the value 0.
Are local automatic variables initialized or not?
It depends on the initialisation syntax that is used, the type of the variable, as well as the storage class.
That would mean int b should be undefined
No, because the example uses value initialisation, and the class in question is an aggregate.
Related
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.
Is the following code valid, e.g. doesn't bring undefined behaviour?
struct S
{
int i = s.i;
static S s;
};
S S::s;
int main()
{
S a; // a.i = 0
S::s.i = 42;
S b; // b.i = 42
}
As far as I know all variables with static storage duration are zero initialized. Hence s.i is 0 on S::s creation, and all is good. But maybe I'm missing something.
I would argue it's well defined.
[class.static.data]/6
Static data members are initialized and destroyed exactly like
non-local variables.
[basic.start.static]/2 (emphasis mine)
A constant initializer for a variable or temporary object o is an
initializer whose full-expression is a constant expression, except
that if o is an object, such an initializer may also invoke constexpr
constructors for o and its subobjects even if those objects are of
non-literal class types. [ Note: Such a class may have a non-trivial
destructor. — end note ] Constant initialization is performed if a
variable or temporary object with static or thread storage duration is
initialized by a constant initializer for the entity. If constant
initialization is not performed, a variable with static storage
duration or thread storage duration is zero-initialized. Together,
zero-initialization and constant initialization are called static
initialization; all other initialization is dynamic initialization.
All static initialization strongly happens before ([intro.races]) any dynamic initialization. [ Note: The dynamic initialization of
non-local variables is described in [basic.start.dynamic]; that of
local static variables is described in [stmt.dcl]. — end note ]
[dcl.init]/6 (emphasis mine)
To zero-initialize an object or reference of type T means:
if T is a scalar type, the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;
if T is a (possibly cv-qualified) non-union class type, each non-static data member, each non-virtual base class subobject, and, if
the object is not a base class subobject, each virtual base class
subobject is zero-initialized and padding is initialized to zero bits;
if T is a (possibly cv-qualified) union type, the object's first non-static named data member is zero-initialized and padding is
initialized to zero bits;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
Because int i = s.i; means s.i goes through dynamic initialization, it's guaranteed to be zero initialized beforehand. So when it'll be used to initialize itself later, it's value won't be indeterminate. A 0 is to be expected.
You are missing something. Variables with static storage duration are zeroed, and then their constructor is called.
What I can't quite tell is whether the initialization of S.i with the value of S.i is undefined behaviour (because S.i is not initialized at this point) or not (because it must be zero).
Edit: The code in Defect Report 2026 is very similar in effect to this, and is declared to be ill-formed (which means the compiler must error). My suspicion is that the intention of the committee is that the OP's code is undefined behaviour.
Edit 2: The above DR refers to constexpr values. That probably changes things enough that is irrelevant.
Having said that: if you are relying on very careful reading of the standard to make your code legal, you are relying on the compiler author to have read it as carefully. You may be right, but that doesn't help in the short-term if the compiler author has misread and implemented something else (although hopefully, they will eventually fix the bug).
In my C++ Primer, 5th Edition, they say on page 43 about default initialization (emphasis mine):
The value of an object of built-in type that is not explicitly initialized depends on where it is defined. Variables defined outside any function body are initialized to zero.
Later, on page 73, they define a new class like this:
struct Sales_data {
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
This is supposed to provide an example of the new standard's in-class initializers. In this case, units_sold and revenue will be initialized to zero. If they are not, they say, the variables will be default-initialized.
But this is my question: What is the point of this in-class initialization? What's wrong with letting them just default-initialize? The reason I ask is that they already mentioned that variables defined outside any function body are initialized to zero, and in this case, these variables are not inside any function - they are in a class definition. So the default-initialization should initialize these variables to zero, shouldn't it?
The quote seems to be in wrong context. A variable can have at least 3 states:
Default initialized: Variable is initialized inside the constructor
based on argument or no argument. Value initialized is a special case of this type
In-class initialized: The C++11 feature which you have presented in
your code
Uninitialized: Variable's initialization is not addressed anywhere
and it can contain any garbage value. Some compilers may automatically make it 0 or give a warning
The first statement about "Variables defined outside any function body" refers to objects with static linkage, i.e., variables declared in namespaces: These are zero initialized. The members in the struct get initialized wherever this struct lives. If it lives on the stack or is allocated on the heap, the built-in variable won't get initialized without the assignments, e.g., when used like this:
void f() {
Sales_data data;
}
Even without the initialization in the declaration, they would get zero-initialized if the struct is used like this, though:
Sales_data global; // <--- the "outside any function body" case
void f() {
Sales_data data0 = {};
Sales_data data1 = Sales_data();
Sales_data data2{};
}
However, these all require cooperation by the user of the struct and initializing them explicitly makes sure the values are set.
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
Not sure of the appropriate title, but it stems from this discussion:
Do the parentheses after the type name make a difference with new?
On Visual Studio 2008, when I run the following code:
struct Stan
{
float man;
};
int main()
{
Stan *s1 = new Stan;
Stan *s2 = new Stan();
}
Examining the locals, s1 has an uninitialized float with a random value. s2 is value initialized to 0.
However, if I add a string data member, the float in both instances is uninitialized.
struct Stan
{
std::string str;
float man;
};
However, the string in both instances is initialized. I tried adding other non-POD classes instead of a string, but the latter case only occurs if I add a string data member. I gather that adding a string still keeps it a POD class? If it wasn't a POD class, then it should have value initialized regardless of the parenthesis, right? Any ideas why floats(and other primitive data types for that matter) aren't initialized when I add a string data member?
Adding a string stops the struct from being a POD class because a POD class must be an aggregate class with no members of type non-POD-struct and std::string has (amongst other things) user-declared constructors which makes it a non-POD-struct.
This is a known bug/feature of Visual Studio 2008. It doesn't support C++03 value initialization for non-POD types such as the structure in your second example.
With the struct as in your second example what should happen is the float is not initialized by new Stan but is zero initialized in new Stan().
Types with a user declared default constructor are initialized by calling that constructor in all cases, this happens correctly.
See here and here.
The behavior that you observe is a conforming behavior from the point of view of C++98 specification of the language.
The type in your first example is a so-called POD (Plain Old Data) type. When you apply the () initializer to a POD class type it performs zero-initialization of all data members of the class.
The type in your second example is not a POD type (because of the non-POD member str). When you apply the () initializer to a non-POD class type, it simply calls the class constructor to perform initialization. In your case the implicit [compiler-provided] constructor will properly initialize the str member, but will not do anything for the man member, which is why you see garbage in it.
Again, this is the correct behavior in C++98. It was changed in C++03. In C++03 the () initializer will perform value-initialization. In accordance with the rules of value-initialization, in your second example, the man field should also get zero-initialized in response to () initializer.
See also https://stackoverflow.com/questions/1976185/what-is-the-difference-between-new-myclass-vs-new-myclass for more detailed explanation .