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.
Related
so in the picture, it says that the problem is with the starting address of the array as we cant change it. but why does this apply only for arrays. int x = 1; we could easily say int y = x; and it would work. doesnt this change the memory address of the variable too?
[tl;dr] The first and sole reason why newValues = oldValues; is illegal ("will not work") is that the C++ standard prohibits it. Array assignment is not defined, supported or allowed in C++, and therefore any such statement is invalid code. Any other attempts to "explain" it, using memory addresses or other speculations, only obfuscates the simple truth that it is the definition of the language that decides what is legal and what is not in that language.
The following are quoted from the posted "textbook" excerpt, which I find to be both wrong and misguided for what looks to be an introduction to C++ basics.
the name of an array without the brackets and subscript stands for the array's starting memory address
Wrong. The name stands for the variable that it denotes, which has array type. While it is true that an array can decay to a pointer ("starting memory address) in certain contexts, it is certainly not true that an array name is the same with its starting address. For example, both sizeof oldValues and typeid(oldValues) are valid expressions, which would mean something very different if replacing oldValues with its memory address.
the statement will not work because you cannot change the starting memory address of an array
The statement "will not work" is correct, but the given reason is still wrong. No assignment changes the address of its left-hand side, it only changes its value. Array assignment does not work because the language does not define it, and for no other reason. Consider for example the following.
int a[4], b[4];
a = b; // error, array assignment not allowed
struct { int n[4]; } c, d;
c = d; // ok, using default copy assignment
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*.
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.
whats is the difference between these three statements in c++ ??
aa *obj;
aa *obj1 = new aa;
aa *obj2 = new aa();
where aa is a class
I am confucion in last two statement .
The first does not initialize the pointer.
In the latest specification,
If the new-initializer is omitted, the object is default-initialized (8.5); if no initialization is performed,
the object has indeterminate value.
Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct initialization.
That is, if the class (you said it was a class) doesn't have a constructor, then the first form will act the same as a local scope definition and leave the memory un-initialized.
The empty initializer will force it to be initialized anyway, which gives the same results as a global variable of that type.
A class might not have a constructor, even a hidden constructor, if it contains nothing but data members of primitive types. You'll see that discussed as a "POD", or plain'ol data. For templates, the difference was found to be annoying, so the rules were refined to work, with (), uniformly for any type, even built-in types. new int() will give a pointer to a value holding 0. new int will give a pointer to a value holding whatever garbage happened to be at that address before.
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).