std::vector<int> foo(5); // creates 5-element int vector
what is the value (or that is the values) of foo?
I understand that it creates a 5-element character vector, but what is the value of each, is it zero or undefined?
When you use this particular constructor of std::vector, the elements of the vector are value initialized.
See http://en.cppreference.com/w/cpp/container/vector/vector for more details on vector::vector.
See http://en.cppreference.com/w/cpp/language/value_initialization for more on value initialization.
For your case, the elements are of type int. That implies each of the elements the vector is initialized to zero.
Related
Consider the following code:
unordered_map<string, vector<string>> hashtable;
string s = "foo";
hashtable[s].push_back("bar");
This seems to work, but that means that in the third line, it is both adding a new entry to the hashtable by initializing a vector of strings at key "foo" as well as adding "bar" to this empty vector. My confusion is how come we don't have to explicitly initialize a vector like:
unordered_map<string, vector<string>> hashtable;
string s = "foo";
vector<string> vec;
vec.push_back("bar");
hashtable[s] = vec;
Adding to my confusion is when we are dealing with stuff like initializing arrays in C++, it is good to explicitly initialize the array like so:
int array[10] = {0);
This is required if we want to make sure the array is initialized with all values being 0 since without it, there could be garbage values stored in memory at the same place the array was initialized at. Going back to my first question with the hashtable, how do we know
hashtable[s].push_back("bar");
isn't pushing "bar" into a vector with garbage values?
I realize my question is not clear at all. Any clarifications with behaviour of [] operator and default values of STL containers is general would be appreciated.
My confusion is how come we don't have to explicitly initialize a vector
This is the expected behavior of std::unordered_map::operator[], which will perform an insertion with value-initialized mapped value if the key does not exist.
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
That means for hashtable[s].push_back("bar");, a value-initialized std::vector (i.e. an empty std::vector) will be inserted at first, then the vector will be returned by reference by std::unordered_map::operator[]. Then push_back("bar") is called on the vector (then its size becomes 1 and contains one element).
isn't pushing "bar" into a vector with garbage values?
No, std::vector is not same as raw array, its size is dynamic. As explained above, the value-initialized std::vector is empty, its size is 0, still doesn't contain any elements (and any "garbage values").
I'm having some problems understanding what const value_type& val means in this function:
void std::vector::resize (size_type n, const value_type& val);
I read the C++ reference and here's what it says:
Object whose content is copied to the added elements in case that n is greater than the current container size.
If not specified, the default constructor is used instead.
Member type value_type is the type of the elements in the container, defined in vector as an alias of the first template parameter (T).
But what exactly does it do? For example I have this line of code:
myVector.resize(10, numeric_limits<double>::infinity());
The content of infinity is copied to myVector if 10 is bigger than its current size?
If someone could please explain, that would be great.
Thank you!
It sets all the values in the vector to that value, so if myVector is empty to begin with, it would contain 10 doubles, with infinity as the value. If you already have the values 1.3, 2.9, 3.6, -1.9 and 5.2 in the vector, the next five elements will be infinity.
Obviously, it makes no difference if you have a value there or what the value is, if the vector was already bigger than 10 elements.
Yes. The resize() function can be used to increase or decrease the size of the vector. However, if you use it to increse the size (if the new size is greater than the current size), something has to go in those new cells. If you don't specify the second parameter then this value is the default constructor for whatever data type the vector holds; however, you can use the second parameter to specify what that default value should be. Common uses of this are to specify a value of 0, NULL, etc.
Despite some elaborate language, it's pretty simple. If the resize creates new elements, then of course they have to be initialized with something. Normally, for a vector<T>, they will be initialized by invoking the default constructor of T. Providing that second argument will instead initialize the new elements to copies of that value.
In your example, indeed, the call ensures that the vector has 10 items, and if it had less than that, all new items receive a copy of infinity. So if your vector had 6 elements, it will get 4 new copies of infinity.
std::vector<std::vector<int>> vecOfVecs;
vecOfVecs.resize(10);
What will be positions 0-9 of vecOfVecs? Instances of std::vector?
If so, is this legitimate:
std::vector<int> *pToVec = &(vecOfVecs[0]);
pToVec->push_back(10);
Yes, positions 0-9 will be empty instances of std::vector<int>, exactly as if you had said
for (size_t i = vecOfVecs.size(); i < 10; ++i) {
vecOfVecs.push_back(std::vector<int>());
}
The "canonical" definition of std::vector::resize in C++03 actually has two parameters, not one, with the second argument being the element value that is used as a "fill value" for the freshly created elements. The second parameter has a default argument equal to a value-initialized object of element type. This means that your call
vecOfVecs.resize(10);
is actually translated into a
vecOfVecs.resize(10, std::vector<int>());
call. I.e. it is actually you who implicitly supplied a default-constructed instance of std::vector<int> to be used as an initializer for all new elements.
Your pToVec->push_back(10) call is perfectly legitimate.
C++11 made some insignificant (in this context) changes to the definition of resize, but the general effect remains the same: the new elements are value-initialized for you. They are ready to be used immediately after the call to resize.
There is a default second parameter of resize that tells what value you'd like to insert into the additional space. If that value is not specified, the default-constructed value is used instead.
void resize (size_type n, value_type val = value_type());
If n is greater than the current container size, the content is expanded by inserting at the end as many elements as needed to reach a size of n. If val is specified, the new elements are initialized as copies of val, otherwise, they are value-initialized.
Your example is entirely legitimate: your vector of vectors will contain ten empty vectors.
std::vector<int> v1(1000);
std::vector<std::vector<int>> v2(1000);
std::vector<std::vector<int>::const_iterator> v3(1000);
How elements of these 3 vectors initialized?
About int, I test it and I saw that all elements become 0. Is this standard? I believed that primitives remain undefined. I create a vector with 300000000 elements, give non-zero values, delete it and recreate it, to avoid OS memory clear for data safety. Elements of recreated vector were 0 too.
What about iterator? Is there a initial value (0) for default constructor or initial value remains undefined? When I check this, iterators point to 0, but this can be OS
When I create a special object to track constructors, I saw that for first object, vector run the default constructor and for all others it run the copy constructor. Is this standard?
Is there a way to completely avoid initialization of elements? Or I must create my own vector? (Oh my God, I always say NOT ANOTHER VECTOR IMPLEMENTATION)
I ask because I use ultra huge sparse matrices with parallel processing, so I cannot use push_back() and of course I don't want useless initialization, when later I will change the value.
You are using this constructor (for std::vector<>):
explicit vector (size_type n, const T& value= T(), const Allocator& = Allocator());
Which has the following documentation:
Repetitive sequence constructor: Initializes the vector with its content set to a repetition, n times, of copies of value.
Since you do not specify the value it takes the default-value of the parameter, T(), which is int in your case, so all elements will be 0
They are default initialized.
About int, I test it and I saw that all elements become 0. Is this standard? I believed that primitives remain undefined.
No, an uninitialized int has an indeterminate value. These are default initialized, i.e.,
int i; // uninitialized, indeterminate value
int k = int(); // default initialized, value == 0
In C++11 the specification for the constructor vector::vector(size_type n) says that n elements are default-inserted. This is being defined as an element initialized by the expression allocator_traits<Allocator>::construct(m, p) (where m is of the allocator type and p a pointer to the type stored in the container). For the default allocator this expression is ::new (static_cast<void*>(p)) T() (see 20.6.8.2). This value-initializes each element.
The elements of a vector are default initialized, which in the case of POD types means zero initialized. There's no way to avoid it with a standard vector.
If I create a vector like vector<myClass> v(10);
what is the default value of each element?
Also, what if it is a vector<myUnion> v(10) ?
The constructor of std::vector<> that you are using when you declare your vector as
vector<myClass> v(10);
actually has more than one parameter. It has three parameters: initial size (that you specified as 10), the initial value for new elements and the allocator value.
explicit vector(size_type n, const T& value = T(),
const Allocator& = Allocator());
The second and the third parameters have default arguments, which is why you were are able to omit them in your declaration.
The default argument value for the new element is the default-contructed one, which in your case is MyClass(). This value will be copied to all 10 new elements by means of their copy-constructors.
What exactly MyClass() means depends on your class. Only you know that.
P.S. Standard library implementations are allowed to use function overloading instead of default arguments when implementing the above interface. If some implementation decides to use function overloading, it might declare a constructor with just a single parameter (size) in std::vector. This does not affect the end result though: all vector elements should begin their lives as if they were value-initialized.
vector<myClass> v;
its a empty vector with size and capacity as 0.
The answer to your second question is similar; vector<myUnion> v(10) will create an array of 10 myUnions initialized with their default constructor. However note that: 1) Unions can't have members with constructors, copy constructors or destructors, as the compiler won't know which member to construct, copy or destroy, and 2) As with classes and structs, members with built-in type such as int will be initialized as per default, which is to say not at all; their values will be undefined.