int i = i;
int main() {
int a = a;
return 0;
}
int a = a surely has undefined behaviour (UB), and more details on it is in
Is reading an uninitialized value always an undefined behaviour? Or are there exceptions to it?.
But what about int i = i? In C++ we are allowed to assign nonconstant values to globals. i is declared and zero initialized (since it has file scope) before the declaration is encountered. In which case we are assigning 0 to it later in the definition.
Is it safe to say this does not have UB?
Surprisingly, this is not undefined behavior.
Static initialization [basic.start.static]
Constant initialization is performed if a variable or temporary object
with static or thread storage duration is constant-initialized. 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 any
dynamic initialization.
Important parts bold-faced. "Static initialization" includes global variable initialization, "static storage duration" includes global variables, and the above clause is applicable here:
int i = i;
This is not constant-initialization. Therefore, zero-initialization is done according to the above clause (for basic integer types zero-initialization means, unsurprising, that it's set to 0). The above clause also specifies that zero initialization must take place before dynamic initialization.
So, what happens here:
i is initialized to 0.
i is then dynamically initialized, from itself, so it still remains 0.
The behavior might be undefined for i, since depending on how you read the standard, you could be reading i before its lifetime starts.
[basic.life]/1.2
... The lifetime of an object of type T begins when:
— its initialization (if any) is complete ...
As mentioned in the other answer, i is initialized twice: first zero-initialized statically, then initialized with i dynamically.
Which initialization starts the lifetime? The first one or the final one?
The standard is being vague, and there are conflicting notes in it (albeit all of them are non-normative). Firstly, there is a footnote in [basic.life]/6 (thanks #eerorika) that explicitly says that the dynamic initialization starts the lifetime:
[basic.life]/6
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated26
...
26) For example, before the dynamic initialization of an object with static storage duration ...
This interpretation makes the most sense to me, because otherwise it would
be legal to access class instances before they undergo dynamic
initialization, before they could estabilish their invariants (including the standard library classes defined by the standard).
There's also a conflicting note in [basic.start.static]/3, but that one is older than the one I mentioned above.
It appears to me int i = i; has undefined behavior, is not caused by the indeterminate value. The term indeterminate value is designed for the objects that have automatic or dynamic storage duration.
[basic.indet#1]
When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced ([expr.ass]).
[basic.indet#2]
If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases...
In your example, the object named i has a static storage duration, hence it is not within the extent of talking about indeterminate value. And, such an object has a zero-initialization that happens before any dynamic initialization as per [basic.start.static#2]
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.
Hence, its initial value is zero. when i is used as an initializer to initialize itself. which is a dynamic initialization and it obeys [dcl.init].
Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression.
It violates the rule in [basic.lifetime]
The program has undefined behavior if:
the glvalue is used to access the object, or
Related
This question already has answers here:
Uninitialized variable behaviour in C++
(4 answers)
Closed 6 months ago.
Why does this print 32767 (or some other random number)? What is std::cout printing? Why is it not NULL (or 0)?
int main()
{
int a;
std::cout << a;
}
That is because variables with automatic storage duration are not automatically initialized to zero in C++. In C++, you don't pay for what you don't need, and automatically initializing a variable takes time (setting to zero a memory location ultimately reduces to machine intruction(s) which are then translated to electrical signals that control the physical bits).
The variable is being reserved a memory location, and it happens that some junk is at that memory location. That junk is being printed out by cout.
As pointed out by #dwcanillas, it is undefined behaviour. Related: What happens to a declared, uninitialized variable in C? Does it have a value?
From the C++ standard (emphasize mine):
8.5 Initializers [dcl.init]
7) To default-initialize an object of type T means:
If T is a (possibly cv-qualified) class type (Clause 9), constructors are
considered. The applicable constructors are enumerated (13.3.1.3), and the best
one for the initializer () is chosen through overload resolution (13.3). The
constructor thus selected is called, with an empty argument list, to initialize >> the object.
If T is an array type, each element is default-initialized.
Otherwise, no initialization is performed.
12) If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.18). [Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. — end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
— If an indeterminate value of unsigned narrow character type (3.9.1) is produced by the evaluation of:
— the second or third operand of a conditional expression (5.16),
— the right operand of a comma expression (5.19),
— the operand of a cast or conversion to an unsigned narrow character type (4.7, 5.2.3, 5.2.9, 5.4), or
— a discarded-value expression (Clause 5)
...
It's undefined behavior. You are printing whatever occupies the memory of a, which in this case happens to be 32767.
The behaviour is covered by C++14 (N3936) [dcl.init]/12:
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced.
[...] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
and your code is not covered by any of the "following cases" which cover a few situations in which unsigned char indeterminate values are allowed to propagate.
Because "a" is not global/static. Its an automatic variable for which initialization happens at run time. If it was global, initialization to zero would have happened at compile time. i.e
• static variables are initialized at compile-time, since their address is known and fixed. Initializing them to 0 does not incur a runtime cost.
• automatic variables can have different addresses for different calls and would have to be initialized at runtime each time the function is called, incurring a runtime cost that may not be needed. If you do need that initialization, then request it.
This question already has answers here:
Uninitialized variable behaviour in C++
(4 answers)
Closed 6 months ago.
Why does this print 32767 (or some other random number)? What is std::cout printing? Why is it not NULL (or 0)?
int main()
{
int a;
std::cout << a;
}
That is because variables with automatic storage duration are not automatically initialized to zero in C++. In C++, you don't pay for what you don't need, and automatically initializing a variable takes time (setting to zero a memory location ultimately reduces to machine intruction(s) which are then translated to electrical signals that control the physical bits).
The variable is being reserved a memory location, and it happens that some junk is at that memory location. That junk is being printed out by cout.
As pointed out by #dwcanillas, it is undefined behaviour. Related: What happens to a declared, uninitialized variable in C? Does it have a value?
From the C++ standard (emphasize mine):
8.5 Initializers [dcl.init]
7) To default-initialize an object of type T means:
If T is a (possibly cv-qualified) class type (Clause 9), constructors are
considered. The applicable constructors are enumerated (13.3.1.3), and the best
one for the initializer () is chosen through overload resolution (13.3). The
constructor thus selected is called, with an empty argument list, to initialize >> the object.
If T is an array type, each element is default-initialized.
Otherwise, no initialization is performed.
12) If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.18). [Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. — end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
— If an indeterminate value of unsigned narrow character type (3.9.1) is produced by the evaluation of:
— the second or third operand of a conditional expression (5.16),
— the right operand of a comma expression (5.19),
— the operand of a cast or conversion to an unsigned narrow character type (4.7, 5.2.3, 5.2.9, 5.4), or
— a discarded-value expression (Clause 5)
...
It's undefined behavior. You are printing whatever occupies the memory of a, which in this case happens to be 32767.
The behaviour is covered by C++14 (N3936) [dcl.init]/12:
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced.
[...] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
and your code is not covered by any of the "following cases" which cover a few situations in which unsigned char indeterminate values are allowed to propagate.
Because "a" is not global/static. Its an automatic variable for which initialization happens at run time. If it was global, initialization to zero would have happened at compile time. i.e
• static variables are initialized at compile-time, since their address is known and fixed. Initializing them to 0 does not incur a runtime cost.
• automatic variables can have different addresses for different calls and would have to be initialized at runtime each time the function is called, incurring a runtime cost that may not be needed. If you do need that initialization, then request it.
Inspired by this question.
We know that global variables with non-constexpr initializers undergo two different "initializations":
First, the "static initialization", which zero-initializes them.
Second, the "dynamic initialization", which uses the user-provided initializer.
Which of those initializations starts the variable lifetime? [basic.life] is being surprisingly unhelpful:
The lifetime of an object ... begins when: ... its initialization (if any) is complete
I see several options:
The last initialization starts the lifetime.
The first initialization starts the lifetime.
Each successive initialization destroys the existing object and creates a new one in its place.
(1) Would make the most sense, but it would make the static initialization of an object that will later be dynamically initialized mostly useless.
(2) Would have interesting effects. E.g. the static init order fiasco is suddenly not UB (by itself) anymore.
(3) Would be very weird.
Indeed, the standard is vague by not specifying how exactly the quoted rule "initialization (if any) is complete" applies to multiple stages of initialization, each of which being referred to as "initialization". And this leaves room for multiple interpretations.
This footnote (non-normative) implies that the lifetime begins only after dynamic initialisation is complete:
[basic.life]
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated 26 ...
26 For example, before the dynamic initialization of an object with static storage duration ([basic.start.dynamic]).
As the other answer makes its argument solely on a non-normative footnote, I will offer a counter-argument based on non-normative note. Not that I have any belief in this interpretation over the other, but I think the standard is in non-normative conflict here, at best.
Note 2 of [basic.start.static]/3 gives an example of unspecified, not undefined, behavior where an implementor (adhering to [basic.start.static]/3) is permitted to perform initialization of a static/thread storage duration variable even if it is not required to be initialized during static initialization (could be during dynamic initialization). The key here being the note's example of why the value of obj1 is unspecified: namely that the value of the object which is used to initialize it may be "fully initialized" or "merely zero-initialized":
[Note 2: As a consequence, if the initialization of an object obj1 refers to an object obj2 potentially requiring dynamic
initialization and defined later in the same translation unit, it is
unspecified whether the value of obj2 used will be the value
of the fully initialized obj2 (because obj2 was statically
initialized) or will be the value of obj2 merely
zero-initialized. For example,
inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
// either statically initialized to 0.0 or
// dynamically initialized to 0.0 if d1 is
// dynamically initialized, or 1.0 otherwise
double d1 = fd(); // either initialized statically or dynamically to 1.0
— end note]
Particularly the comment from the example code snippet:
[d2] either statically initialized to 0.0 or dynamically initialized to 0.0 if d1 is dynamically initialized, or 1.0 otherwise.
Implying that the "otherwise" case, namely where d1 is (dynamically) initialized from the "merely zero-initialized" d2 is not undefined.
I would say, the dynamic initialization begins the lifetime of that object. Since the lifetime is a property defined as that
[basic.life#1]
The lifetime of an object or reference is a runtime property of the object or reference.
Zero-initialization could be said that occurs at a compile-time that is the reason why static initialization requires a constant expression as its initialization, which could be evaluated at compile-time.
The initialization in the normative rule you cited arguably refers to all dynamic initializations that can start the lifetime of an object(at runtime).
given a class who's only member is a char[10], that has no inheritance nor virtual members, that has a constructor that does not mention the array in any way (such that it gets default-initialization -> no initialization, like so:
class in_place_string {
char data[10];
static struct pre_initialized_type {} pre_initialized;
in_place_string(pre_initialized_type) {} //This is the constructor in question
in_place_string() :data() {} //this is so you don't yell at me, not relevent
};
Is it defined behavior to placement-new this class into a buffer that already has data, and then read from the array member?
int main() {
char buffer[sizeof(in_place_string)] = "HI!";
in_place_string* str = new(buffer) in_place_string(in_place_string::pre_initialized);
cout << str->data; //undefined behavior?
}
I'm pretty sure it's not well defined, so I'm asking if this is implementation defined or undefined behavior.
You're not performing a reinterpret_cast (which wouldn't be safe, since the class has non-trivial initialization); you're creating a new object whose member is uninitialized.
Performing lvalue->rvalue conversion on an uninitialized object gives an indeterminate value and undefined behavior. So is the object uninitialized?
According to 5.3.4 all objects created by new-expression have dynamic storage duration. There's no exception for placement new.
Entities created by a new-expression have dynamic storage duration
And then 8.5 says
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.17). [ Note: Objects with static or thread storage duration are zero-initialized, see end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
and the following cases permit only unsigned char, and even then the value is not useful.
In your case the new object has dynamic storage duration (!) and its members for which no initialization is performed have indeterminate value. Reading them gives undefined behavior.
I think the relevant clause is 8.5 [dcl.init] paragraph 12:
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.17). [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. —end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the
following cases:
If an indeterminate value of unsigned narrow character type (3.9.1) is produced by the evaluation of:
the second or third operand of a conditional expression (5.16),
the right operand of a comma expression (5.18),
the operand of a cast or conversion to an unsigned narrow character type (4.7, 5.2.3, 5.2.9, 5.4), or
a discarded-value expression (Clause 5), then the result of the operation is an indeterminate value.
If an indeterminate value of unsigned narrow character type is produced by the evaluation of the right operand of a simple assignment operator (5.17) whose first operand is an lvalue of unsigned narrow character type, an indeterminate value replaces the value of the object referred to by the left operand.
If an indeterminate value of unsigned narrow character type is produced by the evaluation of the initialization expression when initializing an object of unsigned narrow character type, that object is initialized to an indeterminate value.
I don't think any of the exception applies. Since the value is read before being initialized after the object is constructed, I think the code results in undefined behavior.
#include <iostream>
using namespace std;
int weirdVariable = weirdVariable + 1;
int main() {
cout<< weirdVariable ;
return weirdVariable ;
}
I was just wondering how this un-initialized variable is not returning error and returning 1.So my question is, how/why is it returning the value "1". Is this program logically valid? Or is it some flaw?
It's not uninitialized. Variables with static storage duration (like a global variable) are first zero-initialized before any further initialization. So weirdVariable ends up with the value 1.
§3.6.2 [basic.start.init] Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.
If you were to declare wierdVariable as local to main, it would be uninitialized. This will give you undefined behaviour because performing lvalue-to-rvalue conversion (read: using the value of) on an uninitialized object gives undefined behaviour.
§4.1 [conv.lval] If the object to which the glvalue refers is [...] uninitialized, a program
that necessitates this conversion has undefined behavior.
Static and global variables are initialized to 0 by default so it's perfectly normal
The C standard ISO/IEC 9899:1999 a.k.a. C99 (and C++) standards say this must be so. See item 10 in section 6.7.8 ("Initialization") of WG14 N1256 for the exact text (https://stackoverflow.com/a/1294780/1938163)
By the way: it is good practice to initialize static variables, also just to render the code more readable!
static int myvar = 0;
Another drawback of not initializing them: if a compiler doesn't follow the standard, you might get in trouble
With regard to local variables that are both NOT static and NOT global, well, you might skip their initialization but that would yield undefined behavior. Don't really rely on it.