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.
Related
Long time java programmer here, new to C++. I have been working with C-style "traditional" arrays (similar to arrays in java). I understand in C++ we can create a simple array as follows:
Person people[3];
The contents of this array is essentially uninitialized junk values. When I print out the contents of each element in the array, I (believe) am getting the memory address of each element.
for(int i = 0; i < 3; i++){std::cout << &person[i] << std::endl;}
Results:
//Note, I get different results here when I use an enhanced for loop vs an iterator for loop. Weird.
00EFFB6C
00EFFBA8
00EFFBE4
Now, here is the part I have failed to get a clear explanation on. I create a pointer to one of the elements in the array. I then ask for some value back from that pointer. In java, I would expect to get a null pointer, but in C++, that is not happening.
Instead, I get the default value, as though this element is initialized:
Person* person1Ptr = &people[0];//Points to an uninitialized value
std::cout << person1Ptr->getFirstName() << std::endl;//Output: "Default First Name", expected nullptr
When I try to get the first name of an element using a reference, this doesn't work (presumably because the value doesn't exist).
Full paste of code: https://pastebin.com/cEadfJhr
From my research, C++ does NOT fill arrays with objects of the specified type automagically.
How is my person1Ptr returning a value?
I believe the problem stems from this misconception :
From my research, C++ does NOT fill arrays with objects of the specified type automagically.
C++ objects have value semantics. Defining a local variable of type T concretely creates a unique instance of that type, it is not a handle to a potential T. The expression Foo f; is conceptually equivalent to the Java expression Foo f = new Foo();. Additionally, value semantics means assignment usually implies a copy. The C++ expression Foo f; Foo g = f; is conceptually equivalent to the Java expression Foo f = new Foo(); Foo g = f.Clone();.
In the case of an array, defining a local variable Foo f[3]; immediately creates three instances of Foo as elements of the f array. Your misconception may come from the fact that creating an object in C++ does not imply that it has been initialized. An object can exist in an uninitialized state. For example int i; create an int object identified by i but its value is indeterminate. In the case of int i[3]; you would have an array of three int each with indeterminate values.
The rules for initialization are very complicated in C++. In the case of Person people[3]; you have an array that is default initialized.
You are initializing an object of type Person[3]. According to default initialization rules :
if T is an array type, every element of the array is default-initialized;
That means each Person gets its own default initialization. To see what happens, consider that T is Person :
if T is a 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;
So each Person's default constructor will be called to initialize that element. You end up with Person people[3]; defining three default constructed Person objects with default initial values.
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.
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...
I'm reading 'C++ All-in-One for Dummies' by J. P. Mueller and J. Cogswell and stumbled onto this:
#include <iostream>
using namespace std;
int main()
{
int ExpensiveComputer;
int CheapComputer;
int *ptrToComp;
...
This code starts out by initializing all the goodies involved — two integers
and a pointer to an integer.
Just to confirm, this is a mistake and should read '... by declaring', right? It's just strange to me that such basic mistakes still make their way to books.
From the point of view of the language, this is default initialization. The problem is, they are initialized to indeterminate values.
otherwise, nothing is done: the objects with automatic storage duration (and their subobjects) are initialized to indeterminate values.
Default initialization of non-class variables with automatic and dynamic storage duration produces objects with indeterminate values (static and thread-local objects get zero initialized)
Note that any attempt to read these indeterminate values leads to UB.
From the standard, [dcl.init]/7
To default-initialize an object of type T means:
If T is a (possibly cv-qualified) class type ([class]), constructors are considered. The applicable constructors are enumerated
([over.match.ctor]), and the best one for the initializer () is chosen
through overload resolution ([over.match]). 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.
Yes you are correct.
You declared and defined these variables, you did not initialize them!
PS: What is the difference between a definition and a declaration?
This code both declares and defines three variables but does not initialize them (their values are said to be indeterminate).
A variable declaration only must include keyword extern.
Right. Hence, "dummies". :)
We can't even blame this on legacy; historically C programmers would declare* a variable and then "initialize" it later with its first assignment.
But it was never the case that simply declaring a variable, without an initializer, were deemed to be "initializing" it.**
So the wording is just wrong.
* Technically we're talking about definitions, but when we say "declare a variable" we almost always mean defining declarations.
** Though objects with static storage duration do undergo their own zero-initialisation phase before anything else happens, so forgoing initialisation yourself is not a catastrophe in that case. Still, we cannot claim that we have initialised that object.
I understand from the answer to this question that values of global/static uninitialized int will be 0. The answer to this one says that for vectors, the default constructor for the object type will be called.
I am unable to figure out - what happens when I have vector<int> v(10) in a local function. What is the default constructor for int? What if I have vector<int> v(10) declared globally?
What I am seeing is that vector<int> v(10) in a local function is resulting in variables being 0 - but I am not sure if that is just because of my compiler or is the fixed expected behaviour.
The zero initialization is specified in the standard as default zero initialization/value initialization for builtin types, primarily to support just this type of case in template use.
Note that this behavior is different from a local variable such as int x; which leaves the value uninitialized (as in the C language that behavior is inherited from).
It is not undefined behaviour, a vector automatically initialises all its elements. You can select a different default if you want.
The constructor is:
vector( size_type, T t = T() )
and for int, the default type (returned by int()) is 0.
In a local function this:
int x;
is not guaranteed to initialise the variable to 0.
int x = int();
would do so.
int x();
sadly does neither but declares a function.
The constructor you are using actually takes two arguments, the second of which is optional. Its declaration looks like this:
explicit vector(size_type n, const T& value = T())
The first argument is the number of elements to create in the vector initially; the second argument is the value to copy into each of those elements.
For any object type T, T() is called "value initialization." For numeric types, it gives you 0. For a class type with a default constructor, it gives you an object that has been default constructed using that constructor.
For more details on the "magic parentheses," I'd recommend reading Michael Burr's excellent answer to the question "Do the parentheses after the type name make a difference with new?" It discusses value initialization when used with new specifically, but for the most part is applicable to value initialization wherever else it can be used.
By default, vector elements are zero-initialized and not default-initialized. Those are two different but related concepts:
zero-initialization is what is done for static objects not having an explicit initialization and what is done for a member given in the initialized list with an initializer of (). For basic types, the value used is 0 converted to the type.
default-initialization is what is done for not explicitly initialized non static variables and members. For basic types it stay uninitialized.
(And C++0X introduces value-initialization which is still different).
As mentioned by others, what happens is the zero initialization kicks in. I actually use that a lot in my code (outside of vectors and other classes):
some_type my_var = some_type();
This allows me to make sure that my variables are always properly initialized since by default C/C++ do not initialize basic types (char, short, int, long, float, double, etc.)
Since C++11, you also can do so in your class definitions:
class MyClass
{
...
int my_field_ = 123; // explicit initialization
int your_field_ = int(); // zero initialization
};
For vectors, the std library uses T(). Whatever T() is, it will use that default initialization. For a class, it calls the default constructor. For a basic type, it uses zero ('\0', 0, 0.0f, 0.0, nullptr`).
As mentioned by James McNellis and Nawaz, it is possible to set the value used to initialize the vector as in:
std::vector<int> foo(100, 1234);
That feature is also available when you resize your vector (if the vector shrinks, the default value is ignored):
foo.resize(200, 1234);
So that way you can have a default initialization value. However, it's a be tricky since you have to make sure that all your definitions and resize() calls use that default value. That's when you want to write your own class which ensures that the default value is always passed to the vector functions.
However, if you want to have a way to auto-initialize to a specific value, you can mix both features this way:
struct my_value {
int v = 123;
};
std::vector<my_value> foo(100);
// here foo[n].v == 123 for n in [0, 100)
This is my preferred way of dealing with this issue (i.e. if I don't want zero by default). It's an extra .v, but much less prone to mistakes and you don't need to know of the default value when you create a vector of my_value.
Also, for those who think this will be slow, it won't. The struct is like syntactic sugar as far as C++ is concerned. One optimized, it will be exactly the same as a simple std::vector<int> foo(100, 123).
The default initialization for an int type is to initialize it to 0.
This is true of most (if not all) primitive types: char will initialize to (char)0 (or '\0' if you prefer), float will initialize to 0.0f, and any pointer initializes to NULL. For other types, the parameterless constructor is invoked.
In general, the default initialization should happen pretty much whenever you aren't able to specify a constructor (or choose not to).