C++ - value of uninitialized vector<int> - c++

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

Related

How to Initialize all Variables in the program to zero without doing it explicitly in c++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I want to make all the variables which I create in my program to have initialization to zero without doing it explicitly.
For example suppose if I create a variable like below:
int i;
We know that it must contain any garbage value and to make it have value 0 by default we need to declare it like
int i=0;
but I want my all variables in the program to contain garbage value as 0 not any other value.
In my code I want my every variables (which include class variables, global variables, local variables) to automatically initialize to 0 without doing it explicitly.
So what logic I tried is that in C, I have written the "Hello World" program without using main() function. So what I have done in that time is to override the _start function which is the first function called by compiler to set up everything and then call to main(). So I think there must be a function which compiler calls during the creation of a variables and I thought we can set the value 0 to the all variables there. Please help me with this problem. If there exist some other logic to solve this problem you can share with me I am open to all solutions but please don't say to explicitly declare them with the value 0.
As a person who spends much of his working life looking at other people's broken code, I really have to say this, although I doubt it will be popular...
If it matters what the initial value of a variable is, then you should initialize it explicitly.
That's true even if you initialize it to what is, in fact, the default value. When I look at a statement like this:
int i = 0;
I immediately know (or think I know) that the programmer really thought about the value, and set it. If I read this:
int i;
then I assume that the programmer does not care about the value -- presumably because it will be assigned a value later.
So far as automatic variables are concerned, it would be easy enough for the compiler to generate code that zero'd the relevant part of the stack frame on entry to a function. I suspect it would be hard to do in application code; but why would you want to? Not only would it make the program behave in a way that appears to violate the language specifications, it would encourage slopping, unreadable programming practices.
Just initialize your variables, and have done with it. Or, if you don't want to initialize it because you know that the compiler will initialize it in the way you want, insert a comment to that effect. You'll thank yourself when you have to fix a bug five years later.
Default initialization and some words regarding the complexity of initialization in C++
To limit the scope of this discussion, let T be any kind of type (fundamental such as int, class types, aggregate as well as non-aggregate), and the t be a variable of automatic storage duration:
int main() {
T t; // default initialization
}
The declaration of t means t will be initialized by means of default initialization. Default initialization acts differently for different kind of types:
For fundamental types such as int, bool, float and so on, the effect is that t is left in an uninitialized state, and reading from it before explicitly initializing it (later) is undefined behavior
For class types, overload resolution resolve to a default constructor (which may be implicitly or implicitly generated), which will initialize the object but where its data member object could end up in an uninitialized state, depending on the definition of the default constructor selected
For array types, every element of the array is default-initialize, following the rules above
C++ initialization is complex, and there are many special rules and gotchas that can end up with uninitialized variable or data members of variables whence read results in UB.
Hence a long-standing recommendation is to always explicitly initialized you variables (with automatic storage duration), and not rely on the fact that default initialization may or may not result in a fully initialized variable. A common approach is (attempting) to use value initialization, by means of initialization of variable with empty braces:
int main() {
int i{}; // value-initialization -> zero-initialization
SomeAggregateClass ac{}; // aggregate initialization
}
However even this approach can fail for class types if one is not careful whether the class is an aggregate or not:
struct A {
A() = default; // not user-provided.
int a;
};
struct B {
B(); // user-provided.
int b;
};
// Out of line definition: a user-provided
// explicitly-defaulted constructor.
B::B() = default;
In this example (in C++11 through C++17), A is an aggregate, whereas B is not. This, in turn, means that initialization of B by means of an empty direct-list-init will result in its data member b being left in an uninitialized state. For A, however, the same initialization syntax will result in (via aggregate initialization of the A object and subsequent value initalization of its data member a) zero-initialization of its data member a:
A a{};
// Empty brace direct-list-init:
// -> A has no user-provided constructor
// -> aggregate initialization
// -> data member 'a' is value-initialized
// -> data member 'a' is zero-initialized
B b{};
// Empty brace direct-list-init:
// -> B has a user-provided constructor
// -> value-initialization
// -> default-initialization
// -> the explicitly-defaulted constructor will
// not initialize the data member 'b'
// -> data member 'b' is left in an unititialized state
This may come as a surprise, and with the obvious risk of reading the uninitialized data member b with the result of undefined behaviour:
A a{};
B b{}; // may appear as a sound and complete initialization of 'b'.
a.a = b.b; // reading uninitialized 'b.b': undefined behaviour.

int x; int y; int *ptr; is not initialization, right?

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.

Why C++ forbids new T[n](arg...)?

This question seems ancient (since C++98), but a quick search didn't lead me to an answer.
std::size_t n = 100;
std::unique_ptr<int[]> data(new int[n]); // ok, uninitialized
std::unique_ptr<int[]> data(new int[n]()); // ok, value-initialized
std::unique_ptr<int[]> data(new int[n](5)); // not allowed, but why?
What's the rationale behind this restriction, some UDTs cannot be default constructed, so those types cannot be used with new[].
Please don't go astray to suggesting something like std::vector or just say that's how the standard defines it, everyone knows that, but I want to know the reason why new T[n](arg...) is forbidden by the standard.
The first part of the answer to "why is it forbidden" is almost tautological: because it is not allowed by the standard. I know you probably don't like such an answer, but that's the nature of the beast, sorry.
And why should it be allowed anyway? What would it mean? In your very very very simple case, initializing every int with a specific value is fairly reasonable. But then again, for normal (statically allocated) array initialization, the rule is that each element in the right hand side {} is passed to an element of the left hand side array, with extra elements getting default-initialization treatment. Ie,
int data[n] = {5};
would only initialize the first element with 5.
But let's look at another example, which isn't even very contrived, which shows that what you ask for doesn't really make a lot of sense in a general context.
struct Foo {
int a,b,c,d;
Foo(int a=0, int b=0, int c=0, int d=0)
: a(a), b(b), c(c), d(d) {}
};
...
Foo *f = new Foo[4](1,2,3,4); // <-- what does this mean?!?!
Should there be four Foo(1,2,3,4)s? Or [Foo(1,2,3,4), Foo(), Foo(), Foo()]? Or maybe [Foo(1), Foo(2), Foo(3), Foo(4)]? Or why not [Foo(1,2,3), Foo(4), Foo(), Foo()]? What if one of Foo's arguments was rvalue reference or something? There are just soooo many cases in which there is no obvious Right Thing that the compiler should do. Most of the examples I just gave have valid use cases, and there isn't one that's clearly better than the others.
PS: You can achieve what you want with eg
std::vector<int> data(n, 5);
some UDTs don't even have a default ctor, so those types cannot be used with new[]
I'm not sure what you mean by this. E.g. int does not have a default constructor. However, you can initialize it as new int(3) or as new int[n](), as you already know. The event that takes place here is called initialization. Initialization can be carried out by constructors, but that's just a specific kind of initialization applicable to class types only. int is not a class type and constructors are completely inapplicable to int. So, you should not be even mentioning constructors with regard to int.
As for new int[n](5)... What did you expect to happen in this case? C++ does not support such syntax for array initialization. What did you want it to mean? You have n array elements and only one initializer. How are you proposing to initialize n array elements and only one initializer? Use value 5 to initialize each array element? But C++ never had such multi-initialization. Even the modern C++ doesn't.
You seem to have adopted this "multi-initialization" interpretation of new int[n](5) syntax as the one and only "obviously natural" way for it to behave. However, this is not necessarily that clear-cut. Historically C++ language (and C language) followed a different philosophy with regard to initializers that are "smaller" or "shorter" than the aggregate being initialized. Historically the language used the explicitly specified initializers to initialize the sub-objects at the beginning of the aggregate, while the rest of the sub-objects got default-initialized (sticking to C++98 terminology). From this point of view, you can actually see the () initializer in new int[n]() not as your "multi-initializer", but rather as an initializer only for the very first element of the array. Meanwhile, the rest of the elements get default-initialized (producing the same effect as () would). Granted, one can argue that the above logic usually applies to { ... } initializers, not to (...) initializers, but nevertheless this general design principle is present in the language.
It's not clear what int[n](5) would even mean. int[5]{1,2,3,4,5} is perfectly well-defined, however.
I'm going to assume you mean for int[n](...) to construct each array element in the same way with the given arguments. Your use case for such a syntax is for data types without a default constructor, but I posit that you don't actually solve that use case: that for many (most?) arrays of such types, each object needs to be constructed differently.
The original expectation is to allow new T[n](arg…) to call T(arg…) to initialize each element.
It turns out that people don't even agree on what new T[n](arg…) would mean.
I gather some good points from the ansnwers and comments, here's the summary:
Inconsistent meaning. parenthesized initializer is used to initialize the object, in case of an array, the only viable one is () which default initializes the array and its elements. Give T[n](arg…) a new meaning will conflict with the current meaning of parenthesized initializer.
No general way to channel the args. Consider a type T with ctor T(int, Ref&, Rval&&), and the usage new T[n](++i, ref, Rval{}). If the args is supplied literally (i.e. call T(++i, ref, Rval{}) for each), ++i will be called multiple times. If the args is supplied through some temporaries, how can you decide ref will pass by reference, while Rval{} will pass as prvalue?
In short, the syntax seems plausible but doesn't actually make sense and is not generally implementable.

Does int() return 0 or an arbitrary value?

Consider this code:
template <typename T>
void f()
{T x = T();}
When T = int, is x equal to 0 or to an arbitrary value?
Bonus question: and consequently, are arrays (both T[N] and std::array<T, N>) the only types where such a syntax may leave contents with arbitrary values.
T() gives value initialization, which gives zero-initialization for a type other than a class, union or array. (§8.5/7 bullet 3): "otherwise, the object is zero-initialized." For an array, each element of the array is value initialized.
For an array, the content will be of an arbitrary value if it's auto storage class, but zero initialized if it's static storage class -- i.e., global (assuming, of course, that you don't specify any initialization).
Regarding your first question, it is called value-initialization, and is well-covered in the standard (C++11 § 8.5 covers initialization in detail, with the specifics on () initialization and how it eventually leads to zero-initialization, starting with 8.5/16 (covers ()), which leads to 8.5/7 (value-initialization), and finally 8.5/5 (zero-initialization).
Regarding std::array<T,N>, if T is a class-type the constructors will fire for each element (user-provided or default if none are provided by the user). If default construction happens default-initialization will fire (which isn't very exciting). By the standard (8.5/6), each element is default-initialized. For T that is not a class type this is effectively the same as T ar[N]; which as you have pointed out, is indeterminate as well (because it is default initialized, which by the standard "no initialization is performed.".
Finally, if static storage is declared for your fixed array of non-class-type, it resides in zero-filled memory on inception. For automatic storage, its back to "no initialization is performed." as your end-game.
I hope i didn't miss something (and I know i'll hear it if I did). There are lots of interesting questions on SO that cover areas like this. If I get a chance I'll link a few.

Rules for on implicit fields initialization

I have recently fixed a bug in an application of mine: the problem was that an object that resides on the stack had a field left uninitialized.
The object had a class declaration of this type:
struct A{
int somefield, someotherfield;
A(): someotherfield(0) {}
}
and when declaring a local variable (like A var; in a function), somefield was left uninitialized, and so a read of it would return a randomish value.
I was certain that fields of a class, which don't appear in the constructor initialization list, would always get initialized by a synthesized trivial constructor (in the case of an int, a zero value). Evidently I am wrong.
So what are the general rules about implicit field initialization?
classes and structs are initialized by contructor
Basic types int double char short ... are not initialized and contain random numbers
Pointers are not initialized and point to random positions
arrays of classes or structs cause each element to be initialized by its constructor
arrays of basic types or pointers are random.