Safety with referencing uninitalized variables in C++ - c++

(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.

Related

Zero initialization of string and string array (C++)

According to https://en.cppreference.com/w/cpp/language/zero_initialization
In the example provided by the documentation:
std::string s; // is first zero-initialized to indeterminate value
// then default-initialized to ""
Why does zero initialization occur to string s; if the syntax is for static T object;?
Why does zero initialization happen before default initialization and why are both allowed to happen?
The effects of zero initialization are:
If T is a scalar type, the object's initial value is the integral
constant zero explicitly converted to T.
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.
If T is a union type, the first
non-static named data member is zero-initialized and all padding is
initialized to zero bits.
If T is array type, each element is
zero-initialized
If T is reference type, nothing is done.
What if I initialize string array[2] = {"Test1"};? I know that the array will contain "Test1" and empty string "".
But according to the above documentation,
If T is array type, each element is
zero-initialized
The data type is string which is an object / reference type?
If T is reference type, nothing is done.
Nothing is done? I thought maybe a constructor would have been called. Surely an empty string is something?
(Unless otherwise specified, all declarations in this answer are assumed to be in namespace scope.)
Why does zero initialization occur to string s; if the syntax is for
static T object;?
Why does zero initialization happen before
default initialization and why are both allowed to happen?
Variables with static storage duration are first zero-initialized at compile time, and then optionally dynamically initialized at runtime. static T object; declares an object of static storage duration. For a simple declaration like
int x;
The dynamic initialization is not performed. For a more sophisticated declaration like
std::string s;
Zero-initializing a string may result in an invalid string with a broken class invariant. Therefore, the dynamic initialization calls the default constructor to ensure that the object is valid.
What if I initialize string array[2] = {"Test1"};? I know that the
array will contain "Test1" and empty string "".
First, at compile time, the two objects are zero-initialized, resulting in possible invalid state. Then, at runtime, the constructors are called (const char* constructor for the first object and default constructor for the second object), and the valid objects are constructed.
The data type is string which is an object / reference type?
std::string is an object type instead of a reference type.
[For a reference type] Nothing is done? I thought maybe a constructor
would have been called. Surely an empty string is something?
A reference type is not considered an actual "object", so there is no point in specifying its zero-initialization semantics.
Why does zero initialization occur to string s; if the syntax is for static T object;?
Why does zero initialization happen before default initialization and why are both allowed to happen?
In page you linked to, that defines a non-local variable.
Non-local variables are initialized in two phases.
Static intialization.
Dynamic initialization, if it applies.
In static initialization phase, a variable is initialized using constant initialization or zero initialization
Dyanmic initialization is used, if it applies, such as for objects that have the appropriate constructor or for objects that are initialized using an expression that can be evaulated at run time.
You can read more on the topic at https://en.cppreference.com.
Nothing is done? I thought maybe a constructor would have been called. Surely an empty string is something?
A reference cannot be zero-initialized. It can only be initialized using a object that it will be a reference to.

Declaring array and printing [BUG?]

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

Pointers Default initialized Value is not NULL?

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...

Range of indexes not default initialized in arrays in C++

The following is the code I am trying to run
#include<bits/stdc++.h>
using namespace std;
int main()
{
bool x[101010];
for(int i=0;i<101010;i++)
{
if(x[i])
cout<<i<<" ";
}
return 0;
}
As far as I know, the default value of boolean type variables is false. However, for the above code from index 94758-101008 value of i is being printed which means they are default initialized as true.
Can anyone please help me in figuring out where am I going wrong?
Your problem can be reduced to this:
bool x;
std::cout << x;
A boolean is a fundamental type. Default initializing automatic variables of a fundamental type leaves them with indeterminate values. Not false, but indeterminate. Using those values leads to undefined behavior. This is what you are seeing.
The reason you see random values is that "behind the curtain" a boolean is an integer type that the compiler enforces only two values on. But if you don't initialize it explicity, you'll get whatever random junk is that memory.
The solution is to explicitly value-initialize your variables. For an array, it would look like this:
bool x[101010]{};
That will recursively value initialize each element of the array, and to value initialize a bool is indeed to set it to false.
the default value of boolean type variables is false.
It's not true here. For default initialization,
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.
x is declared as local object with automatic storage duration, and it's an array with non-class type; then the value of all the elements of x will be indeterminate values.

How are local and global variables initialized by default?

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