How new int[n]() works? - c++

I am curious about new int[n]() operator, as per my knowledge it uses to initialize the array values to zero which is created using the new operator. But I can't use some value in parenthesis like new int[n](x) to initialize values to x, why I can't do that, What happens at the compiler level when I use new int[n]()?

int is a POD and per C++11 you value initialize the array. In the case of int it is 0.
The reason it doesn't work with value in parantheses is because it is not defined. If you insist (for educational reason) you can overload the new operator to do what you want.
You can initialize the array with initializer list though:
int* a = new int[10]{10, 6};
However it will initialize the first two elements in this example.

new invokes a constructor call on int[n](), which is what is setting it to 0. When you call it as new int[n], you are simply default initializing the array. Meaning the memory is only allocated, and not set.
new int[n]() is value-initializing your array, both allocating space and initializing each int, like int(). This is why it is set to 0, and cannot be set to anything else by invoking int(x); there is no int constructor that can use x in that way. Calling int(x) would be read as a functional style cast, and not a constructor of type int.

Related

C++ Pointers and C-style array initialization

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.

What happens when we create a parameterized constructor with a pointer arguement?

For example, can you explain what would happen in the following code?
class Vector{
int v[3];
Vector(int *x);//parameterized constructor created
};
Vector::Vector(int *x)//definition of the parameterized constructor
{
for (int i=0;i<size;i++)
v[i]=x[i];//what happens here?? why did we take pointer as arguement?
}
From my understanding, by putting v[i]=x[i] we created a new array in which all elements of v are now in x. Why did this require a pointer argument? Couldn't it have been done with a reference &?
This goes back to older style C habits, when you can use a pointer as an array, by "indexing" it's elements.
Taken from: https://en.wikibooks.org/wiki/C_Programming/Pointers_and_arrays
A variable declared as an array of some type acts as a pointer to that type. When used by itself, it points to the first element of the array.
A pointer can be indexed like an array name.
However, a few notes:
v[i]=x[i] we created a new array
No, you did not create a new array here, the array was already created when the body of the constructor got executed. What happens here is that TO the value v[i] we will assign the value of: *(x + i) ie. the ith. element from the address x points to. Unless you know how x was created and initialized this is pretty dangerous code. Just imagine you can call this method with the address of a single int. I suppose, size is 3 or less, otherwise this code has serious security issues.
You always should check for null pointers, before trying to access the value they point to.
You can pass in the array by reference if you know the size of x at compile time:
Vector(int (&x)[3]);
If you don't know the size at compile time then what you're doing goes from being unsafe code, to blatantly wrong code.
Another option is to use std::array if you know the size at compile time, and std::vector if you don't.
Just to add a bit to previous answers, the indexing operator [] actually dereferences a pointer and shifts it by index*sizeof(type) at the same time. The same relates to declaration of an array. Say, if you declare int a[1]; this means that a is now a pointer to int, i.e. int*. So if you wanted to pass it to a function as an argument, you would need to specify its type as int*.

Difference between various initializers in C++

I've only recently started learning C++ as part of my 10th Grade syllabus, and am only aware of the basics, thus simple answers (if possible) will be appreciated.
I'm rather confused between initialization and assignment.
//Case 1
int a=5; //This is initialization
a=6; //This is assignment
From what I've understood, a variable is initialized when you give it a value to hold while declaring it. Changing this later in the code will be an assignment. Right?
What about :
//Case 2
int b;
{
//Block of code which does not call variable b
.
.
.
//End of block
}
b=6; // Is this initialization as well?
While 'b' is uninitialized when we declare, we later assign the value '6'. Can we say the 'b' is initialized now? Or are the terms initialized and uninitialized not applicable to 'b' anymore?
I read the an uninitialized variable holds "garbage values" till it isn't initialized. What exactly are "garbage values"?
What is the difference between the following initializers : '()', '{}', and '='?
Okay, once you declare a variable without assigning any value, like
int b;
that means that the compiler reserves some space in the memory to hold the value (to be exact, in this case the memory is reserved on the stack). But since you didn't assign any value to the variable, it still holds the value, that the assigned space in memory had before. And that can be anything. Those are garbage values.
Initializers:
int b(1);
assigns the value 1 to be (in general, it calls a constructor of the type)
The brackets can be used to initialize arrays like this (edit):
int b[] = {1, 3, 5, 7};
And the = just assigns a value. The difference between this and the first will only become interesting when dealing with more complex types (classes), where you have constructors
Easilly spoken:
Uninitialize variable:
int a;
You are declare a variable that means you allocate memory but dont assign a value to it. So its compiler dependend if the value is set to 0 or not. So there could be anything in. Thats waht you called garbage values.
Initialized variable:
int a = 0;
You are declare a variable that means you allocate memory and assigne a value to it.
Assigne Values:
a = 10;
You assigne a rvalue (in this case 10) to a lvalue ( a). So you dont allocate new memory.
You're basically right.
Some older texts call the first assignment to an uninitialised variable an "initialisation", although this is not strictly accurate.
"Garbage values" are arbitrary values. They could look meaningful or could be totally random.
Initialization serves to initialize an uninitialized value.
It can be done my means of copy constructor, i.e. int a = 1; or int a(1);, it can be done by means of assignment, i.e. int a; a = 1;, it can be done via a function, i.e. int a; init(a);. Initialization is not a "language thing", it is just the act of specifying an unspecified value.
A "garbage value" is an arbitrary value. Some storage will be given to the uninitialized object, and attempting to read it will produce a value of whatever happened to be in that memory.

Initialization of a pointer to an array of int

I have been mucking around with C++ once again and noticed a strange behavior regarding the initialization of an array when declared as a pointer inside a class member method or inside the main() function.
int * p = new int[20];
What I would expect to happen is that the pointers will remain uninitialized with random values as they do with
int arr[20];
But instead they are all zeroed. What is going on?
Even though they're zero (this is loosely put, see below), they're not initialized.
Actually, you can't tell they're zero, because if you read the values, you run into undefined behavior. You can't read an un-initialized variable.
To have the array value-initialized, you can do:
int * p = new int[20]();
// ^^
// note parenthesis
but otherwise no, it's not initialized.
p is a pointer to an integer, and it is initialized with the result of a new[] expression. That expression returns the address of the first element of a dynamically allocated array of integers. The array itself is not initialized and contains indeterminate values. If you had said new int[100](), the array would have been zero-initialized instead.

How to initialise memory with new operator in C++?

I'm just beginning to get into C++ and I want to pick up some good habits. If I have just allocated an array of type int with the new operator, how can I initialise them all to 0 without looping through them all myself? Should I just use memset? Is there a “C++” way to do it?
It's a surprisingly little-known feature of C++ (as evidenced by the fact that no-one has given this as an answer yet), but it actually has special syntax for value-initializing an array:
new int[10]();
Note that you must use the empty parentheses — you cannot, for example, use (0) or anything else (which is why this is only useful for value initialization).
This is explicitly permitted by ISO C++03 5.3.4[expr.new]/15, which says:
A new-expression that creates an object of type T initializes that object as follows:
...
If the new-initializer is of the form (), the item is value-initialized (8.5);
and does not restrict the types for which this is allowed, whereas the (expression-list) form is explicitly restricted by further rules in the same section such that it does not allow array types.
There is number of methods to allocate an array of intrinsic type and all of these method are correct, though which one to choose, depends...
Manual initialisation of all elements in loop
int* p = new int[10];
for (int i = 0; i < 10; i++)
p[i] = 0;
Using std::memset function from <cstring>
int* p = new int[10];
std::memset(p, 0, sizeof *p * 10);
Using std::fill_n algorithm from <algorithm>
int* p = new int[10];
std::fill_n(p, 10, 0);
Using std::vector container
std::vector<int> v(10); // elements zero'ed
If C++11 is available, using initializer list features
int a[] = { 1, 2, 3 }; // 3-element static size array
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime
Assuming that you really do want an array and not a std::vector, the "C++ way" would be this
#include <algorithm>
int* array = new int[n]; // Assuming "n" is a pre-existing variable
std::fill_n(array, n, 0);
But be aware that under the hood this is still actually just a loop that assigns each element to 0 (there's really not another way to do it, barring a special architecture with hardware-level support).
Possible ways of initializing the plain dyanmic array. Choose the one as per your requirement.
int* x = new int[5]; // gv gv gv gv gv (gv - garbage value)
int* x = new int[5](); // 0 0 0 0 0
int* x = new int[5]{}; // 0 0 0 0 0 (Modern C++)
int* x = new int[5]{1,2,3}; // 1 2 3 0 0 (Modern C++)
If the memory you are allocating is a class with a constructor that does something useful, the operator new will call that constructor and leave your object initialized.
But if you're allocating a POD or something that doesn't have a constructor that initializes the object's state, then you cannot allocate memory and initialize that memory with operator new in one operation. However, you have several options:
Use a stack variable instead. You can allocate and default-initialize in one step, like this:
int vals[100] = {0}; // first element is a matter of style
use memset(). Note that if the object you are allocating is not a POD, memsetting it is a bad idea. One specific example is if you memset a class that has virtual functions, you will blow away the vtable and leave your object in an unusable state.
Many operating systems have calls that do what you want - allocate on a heap and initialize the data to something. A Windows example would be VirtualAlloc().
This is usually the best option. Avoid having to manage the memory yourself at all. You can use STL containers to do just about anything you would do with raw memory, including allocating and initializing all in one fell swoop:
std::vector<int> myInts(100, 0); // creates a vector of 100 ints, all set to zero
Yes there is:
std::vector<int> vec(SIZE, 0);
Use a vector instead of a dynamically allocated array. Benefits include not having to bother with explicitely deleting the array (it is deleted when the vector goes out of scope) and also that the memory is automatically deleted even if there is an exception thrown.
Edit: To avoid further drive-by downvotes from people that do not bother to read the comments below, I should make it more clear that this answer does not say that vector is always the right answer. But it sure is a more C++ way than "manually" making sure to delete an array.
Now with C++11, there is also std::array that models a constant size array (vs vector that is able to grow). There is also std::unique_ptr that manages a dynamically allocated array (that can be combined with initialization as answered in other answers to this question). Any of those are a more C++ way than manually handling the pointer to the array, IMHO.
std::fill is one way. Takes two iterators and a value to fill the region with. That, or the for loop, would (I suppose) be the more C++ way.
For setting an array of primitive integer types to 0 specifically, memset is fine, though it may raise eyebrows. Consider also calloc, though it's a bit inconvenient to use from C++ because of the cast.
For my part, I pretty much always use a loop.
(I don't like to second-guess people's intentions, but it is true that std::vector is, all things being equal, preferable to using new[].)
you can always use memset:
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
For c++ use std::array<int/*type*/, 10/*size*/> instead of c-style array. This is available with c++11 standard, and which is a good practice. See it here for standard and examples. If you want to stick to old c-style arrays for reasons, there two possible ways:
int *a = new int[5]();
Here leave the parenthesis empty, otherwise it will give compile error. This will initialize all the elements in the allocated array. Here if you don't use the parenthesis, it will still initialize the integer values with zeros because new will call the constructor, which is in this case int().
int *a = new int[5] {0, 0, 0};
This is allowed in c++11 standard. Here you can initialize array elements with any value you want. Here make sure your initializer list(values in {}) size should not be greater than your array size. Initializer list size less than array size is fine. Remaining values in array will be initialized with 0.
Typically for dynamic lists of items, you use a std::vector.
Generally I use memset or a loop for raw memory dynamic allocation, depending on how variable I anticipate that area of code to be in the future.