How do we know pointers are not initialized to NULL by default?
There is a similar questions directed at Why aren't pointers initialized with NULL by default?
Just for checking, here is a very simple code just to see if a pointer is set to NULL by default.
#include <iostream>
using namespace std;
int main()
{
int* x;
if(!x)
cout << "nullptr" << endl;
return 0;
}
and at the output, I received nullptr message. I appreciate if someone can clarify this.
How do we know pointers are not initialized to NULL by default?
Because we know that the standard says that default initialised pointer has an indeterminate value if it has automatic or dynamic storage. Quote from the standard (draft):
[dcl.init] 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. ...
And further:
[dcl.init] To default-initialize an object of type T means:
— If T is a (possibly cv-qualified) class type [pointer isn't a class, so we don't care]
— If T is an array type [pointer isn't an array, so we don't care]
— Otherwise, no initialization is performed.
I have declared a char (and also int) pointer without initializing it , and I got null pointers.
Reading an indeterminate value has undefined behaviour. Quote from the standard (draft):
[dcl.init] ... If an indeterminate value is produced by an evaluation, the behavior is undefined except in the
following cases: [cases which don't apply here]
The question you linked to handles variables with local storage duration exclusively, so I assume you refer to these as well.
Such variables are not initialised if you don't do so yourself, so they get the value of whatever was written in their memory location before (standard wording: their value is 'indeterminate') – nothing speaks against, though, that this memory already is zero – by pure accident!
You can try the following:
void test()
{
int* p; // uninitialized
std::cout << p << std::endl; // undefined behaviour!!!
// (that's what you most likely did already...)
// now something new: change the memory...
p = reinterpret_cast<int*>(static_cast<uintptr_t(0xaddadaad));
}
int main()
{
test();
// again something new: call it a SECOND time:
test();
}
As this is undefined behaviour there are no guarantees at all that you will get any meaningful output – chances are, though that the memory of first function call is reused in second one and you might get output ressembling to the following:
00000000
addadaad
So even if there just happened to be all zero memory at programme start, it might differ from that at some later point while your programme is running...
Related
struct A
{
int x;
}
A t{};
t.x = 5;
new (&t) A;
// is it always safe to assume that t.x is 5?
assert(t.x == 5);
As far as I know, when a trivial object of class type is created, the compiler can omit the call of explicit or implicit default constructor because no initialization is required.
(is that right?)
Then, If placement new is performed on a trivial object whose lifetime has already begun, is it guaranteed to preserve its object/value representation?
(If so, I want to know where I can find the specification..)
Well, let's ask some compilers for their opinion. Reading an indeterminate value is UB, which means that if it occurs inside a constant expression, it must be diagnosed. We can't directly use placement new in a constant expression, but we can use std::construct_at (which has a typed interface). I also modified the class A slightly so that value-initialization does the same thing as default-initialization:
#include <memory>
struct A
{
int x;
constexpr A() {}
};
constexpr int foo() {
A t;
t.x = 5;
std::construct_at(&t);
return t.x;
}
static_assert(foo() == 5);
As you can see on Godbolt, Clang, ICC, and MSVC all reject the code, saying that foo() is not a constant expression. Clang and MSVC additionally indicate that they have a problem with the read of t.x, which they consider to be a read of an uninitialized value.
P0593, while not directly related to this issue, contains an explanation that seems relevant:
The properties ascribed to objects and references throughout this document apply for a given object or reference only during its lifetime.
That is, reusing the storage occupied by an object in order to create a new object always destroys whatever value was held by the old object, because an object's value dies with its lifetime. Now, objects of type A are transparently replaceable by other objects of type A, so it is permitted to continue to use the name t even after its storage has been reused. That does not imply that the new t holds the value that the old t does. It only means that t is not a dangling reference to the old object.
Going off what is said in P0593, GCC is wrong and the other compilers are right. In constant expression evaluation, this kind of code is required to be diagnosed. Otherwise, it's just UB.
From looking at the Standard, the program has undefined behavior because of an invalid use of an object with indeterminate value.
Per [basic.life]/8, since the object of type A created by the placement new-expression exactly overlays the original object t, using the name t after that point refers to the A object created by the new-expression.
In [basic.indet]/1, we have:
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]).
One important detail here (which I missed at first) is that "obtaining storage" is different from "allocating storage" or the storage duration of a storage region. The "obtain storage" words are also used to define the beginning of an object's lifetime in [basic.life]/1 and in the context of a new-expression in [expr.new]/10:
A new-expression may obtain storage for the object by calling an allocation function ([basic.stc.dynamic.allocation]). ... [ Note: ... The set of allocation and deallocation functions that may be called by a new-expression may include functions that do not perform allocation or deallocation; for example, see [new.delete.placement]. — end note ]
So the placement new-expression "obtains storage" for the object of type A and its subobject of type int when it calls operator new(void*). For this purpose, it doesn't make a difference that the memory locations in the storage region actually have static storage duration. Since "no initialization is performed" for the created subobject of type int with dynamic storage duration, it has an indeterminate value.
See also this Q&A: What does it mean to obtain storage?
this might be a noob question, but still i am so confused why this happens.
So this code works just fine:
int *m,g;
g=1;
m[0]=1;
cout<<m[0];
and this one reports error:
int *m;
m[0]=1;
cout<<m[0];
Could this be a bug?
You are using an uninitialized array and you try to access it causing you an undefined behaviour
according to the standard
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
you should initialized like this before
int *m=new int[size_you_want_give_to]
eg
int *m=new int[5]; // array of 5 elements
(Assuming includes/namespace std/prototypes in the lines above code)
1) Is it safe to create a reference to a declared variable that isn't initialized?
myVariable is declared in line 2 and then myRef is set to reference the uninitialized myVariable in line 3.
Is this something that shouldn't be done?
1- int main(){
2- string myVariable;
3- string& myRef = myVariable;
4- {
2) Is it safe to initialize an uninitialized variable by passing itself through as a reference to a function?
myVar is declared on line 2 and then initialized on line 3 but it uses its uninitialized self as an arguement in the function askText. Inside the function on line 3('7'), the reference text_to_initialize gives myVar a value finally.
Is it safe to intialize with yourself as an arguement in line 3?
1- int main(){
2- string myVar;
3- myVar = inputText(myVar);
4- }
5-
6- string inputText(string& text_to_initialize){
7- cin >> text_to_initialize;
8- return (text_to_initialize + "!");
8- }
All of the above are ok, since none of them perform lvalue-to-rvalue conversion on the indeterminate value. It's even permitted to bind a reference to a variable with non-trivial initialization before that initialization has completed.
The rule is found in section 8.5:
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:
and the cases involve narrow character types, so not applicable here. What is important is that no evaluation produces an indeterminate value (which would happen as a result of lvalue-to-rvalue conversion).
As John points out, in your particular case, the default initialization of a std::string is not "no initialization", so you don't even have an indeterminate value to begin with. But you'd be ok even for primitive types with no default initialization.
C++11 §12.1/14:
During the construction of a const object, if the value of the object or any of its subobjects is accessed through an lvalue that is
not obtained, directly or indirectly, from the constructor’s this
pointer, the value of the object or subobject thus obtained is
unspecified. [Example:
struct C;
void no_opt(C*);
struct C {
int c;
C() : c(0) { no_opt(this); }
};
const C cobj;
void no_opt(C* cptr) {
// value of cobj.c is unspecified
int i = cobj.c * 100;
cptr->c = 1;
// value of cobj.c is unspecified
cout << cobj.c * 100 << '\n';
}
Compiling the above example outputs 100. My question is why is the value of cobj.c should be unspecified when the initialization list sets it to 0 before entering constructor? How is this behavior different in case if a non-const object is used?
Genuinely const objects may be treated by the compiler as legitimate constants. It can assume their values never change or even store them in const memory, e.g. ROM or Flash. So, you need to use the non-const access path provided by this as long as the object is, in fact, not constant. This condition only exists during object construction and destruction.
Offhand, I think there does not need to be a corresponding requirement for destructors because the object lifetime has already ended and cobj.c is inaccessible as soon as the destructor for cobj begins.
As Matthieu mentions, it is a strong "code smell" to be accessing an object besides through this during construction or destruction. Reviewing C++11 §3.8 [basic.life] ¶1 and 6, it would appear that cobj.c inside the constructor is UB for the same reason it is inside the destructor, regardless of the object being const or §12.1/14, because its lifetime does not begin until initialization is complete (the constructor returns).
It might be likely to work, but it will ring alarms for good C++ programmers, and by the book it is illegal.
The reason for the quoted rule is to allow the compiler to make
optimizations based on the const-ness of the object. For example,
depending on optimization, your compiler might replace the second
cobj.c * 100 in no_opt with i. More likely, in this particular
case, the optimizer will suppress the i and its initialization
completely, so the code will appear to work. But this might not be the
case if you also output i, before changing cptr->c; it all depends
on how agressive the compiler optimizes. But the compiler is allowed to
assume that *cptr is not an alias for cobj, because cobj is a
const object, where as you modify through *cptr, so it cannot point to
a const object without undefined behavior.
If the object isn't const, of course, the issue doesn't occur; the
compiler must always take into account a possible aliasing between
*cptr and cobj.
Based on below, am i right?
global_A reference is initialized to null.
global_int is 0
local_A reference is null
local_int is uninitialized
Both global_A.x and local_A.x is uninitialized.
THanks for any help.
A global_A;
int global_int;
class A {
public : int x;
}
int main()
{
int local_int;
A local_A;
}
Building up on Andrey's response.
$3.6.2- "Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.". In OP, "global_A" and "global_int" have static storage duration. "local_int" and "local_A" have no linkage as these are local objects.
$8.5/5- To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the
object is set to the value of 0 (zero)
converted to T;
— if T is a non-union class type, each
nonstatic data member and each
base-class subobject is
zeroinitialized;
— if T is a union type, the object’s
first named data member89) is
zero-initialized;
— if T is an array type, each element
is zero-initialized;
— if T is a reference type, no
initialization is performed.
$6.7.4/4- "The zero-initialization (8.5) of all local objects with static storage duration (3.7.1) is performed before any other initialization takes place. A local object of POD type (3.9) with static storage duration initialized with constant-expressions is initialized before its block is first entered. An implementation is permitted to perform
early initialization of other local objects with static storage duration under the same conditions that an implementation is permitted to statically initialize an object with static storage duration in namespace scope(3.6.2). Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control re-enters the declaration (recursively) while the object is being initialized, the behavior is undefined."
EDIT 2:
$8.5/9- "If no initializer is
specified for an object, and the
object is of (possibly cv-qualified)
non-POD class type (or array thereof),
the object shall be
default-initialized; if the object is
of const-qualified type, the
underlying class type shall have a
user-declared default constructor.
Otherwise, if no initializer is specified for a nonstatic object, the
object and its subobjects, if any,
have an indeterminate initial
value90); if the object or any of
its subobjects are of const-qualified
type, the program is ill-formed."
In general, you want to read up these sections along with $8.5 for good hold on this aspect.
There are no references in your code, so any of your points that mention "references" make no sense.
In your example, both global object - global_int and global_A - are zero-initialized. Both local objects - local_int and local_A - contain indeterminate values, which means that local_int and local_A.x are not initialized.
P.S. Of course, as other already noted, your code is non-compilable. You can't declare A objects before declaring class A (and you are missing a ; after the class definition).
Basically, whenever you declare a variable, the compiler will call its default constructor unless you specify otherwise.
The language level types (e.g. pointers, 'int', 'float', 'bool', etc) "default constructor" does absolutely nothing, it just leaves the memory as it is when it is declared (global/static variables are special cases, refer to chubsdad's answer for more on the specifics). This means that they can be pretty much anything because you usually can't be sure what was in that memory previously or even where the memory came from (except in the case of the 'placement new' operator).
The class you created has no constructors so the compiler will generate a default constructor for you which simply calls the constructor of each of its members/variables. If you incorporate the information provided in the previous paragraph, you can see that the variable 'x' will have its default constructor called, which does nothing, and thus is isn't initialized to any value.
As others have said, there are no references in your code or pointers, so the term 'NULL' is invalid in all cases here. NULL usually refers to a pointer which, like other language level types, doesn't get set to anything until you assign it a value (unless of course its a global/static variable).
Just for the sake of completeness if you had references:
References must be initialized on declaration, otherwise you get punished by a compiler error. This means a reference always needs another value or reference it refers to (like the says), this is ensured by the compiler so you cannot forget it. This also implies that references can never be null pointers. However the object they refer to might become invalid.
global_A and local_A are not references; they are objects and created using their default constructors. Default constructor has not been specified so it will be generated, which will do nothing so the member variable will remain uninitialized.
A global_A;
This is an instace, not a pointer, your program will call the constructor before entering main.
To get a pointer to an instance and not an instance you have to write:
A* global_A;
global_int is initialized to 0, as all global variables are initialized to their defaults.
The variable A local_A will be initialized every time your program enters the function in which it is declared by a call to its constructor.
As before if you want a pointer to A you have to write A *local_A, but this time you have to initialize it to NULL yourself.
A *local_A = NULL;
The varialle local_int wont be initialized as it is a primitive type.
If local_A.x is initialized depends on the constructor of A, the default constructor will not initialize local_A.x. If x where a class instance creating an instance of A will initialize x with the constructor of its class.
They all require to be initialized. The compiler will give you a warning about this.
This code won't compile unless you forward declare A.
global_A reference is initialized to null - No, it will reference an A object.
global_int is 0 - Think so, need to check.
local_A reference is null - No, same as with global_A.
local_int is uninitialized - Yes, it will get some garbage value.
Both global_A.x and local_A.x is uninitialized - Yes.
You can always debug and see for yourself.
well guys .. i am more confused as i see responses from here. Anyway i did a test as shown below:
1 #include
2 using namespace std;
3
4 class A {
5
6 public :
7 A() : x(9) {};
8 int x;
9
10 };
11
12 A global_a;
13 int global_b;
14
15 int main() {
16
17 A local_a;
18 int local_b;
19 cout << "global_a.x = " << global_a.x << '\n';
20 cout << "local_a.x = " << local_a.x << '\n';
21
22 cout << "global_b = " << global_b << '\n';
23 cout << "local_b = " << local_b << '\n';
24
25 }
Results using my g++ compiler on ubuntu linux:
global_a.x = 9
local_a.x = 9
global_b = 0
local_b = 0
I do think local_b should be undefined but somehow compiler initialized it by default. However local_a .. i am not sure if that should be initialized by default. From the testing here .. local_a seem to be initialized. Not sure if that complies with standard c++ specification (eg C++ PRimer 4th edition says default constructor is used regardless where a class variable is declared - does that means variable of class type is initialized whether it is global or local?).
Whatever it is .. it is one big hell of confusion. Maybe i should quit learning C++. Java is so much more straight forward. Hell yeahhh!!
global_A reference is initialized to
null.
No, its a valid object (constructed based on default constructor, which you don't have in your code but compiler adds that)
global_int is 0
yes
local_A reference is null
no, same reason as for global
local_int is uninitialized
no, its initialized to 0
Both global_A.x and local_A.x is
uninitialized.
no both are initialized to 0