Initializing a vector with part of an array? - c++

int arr[5] = {0,1,2,3,4};
vector<int> vec;
normally we do:
vector<int> vec(arr, arr + sizeof(arr) / sizeof(int));
but how do initialize a vector vec with only first 3 values of arr?
Also how do I initialize it with the middle 3 values?
I have to initialize it right away, no push_back on multiple lines..

The constructor form you are invoking is this**:
template <class Iterator> vector(Iterator start, Iterator end);
So, you may pass in anything that acts like a pair of iterators. Specifically, you may pass in two pointers, as long as they both point into the same array, and as long as the 2nd doesn't come before the first (if the pointers are equal, they represent an empty range).
In your example, you pass in a pointer to the first element of the array and a pointer to the (mythical) elment-after-the-last-element of the array:
vector<int> vec(arr, arr + sizeof(arr) / sizeof(int));
Generally, you may pass in a pointer to any element as the start, and a pointer past any element as the finish.
but how do I initialize a vector vec with only first 3 values of arr?
Pass in pointers to the first and one past the third elements:
vector<int> vec(arr, arr+3);
Also how do I initialize it with middle 3 values?
Pass in a pointer to the first item you want to copy, and a pointer to one paste the final element. In this case, indexes 1 and 4:
vector<int> vec(arr+1, arr+4);
** Okay, it is slightly more complicated than that, but it's okay to pretend for the sake of this discussion. The actual form is: template <class InputIterator>
vector( InputIterator first, InputIterator last,
const Allocator& alloc = Allocator() );

Related

C++ initialization of vector

Could anybody explain to me why we can initialize a vector this way?
int a[]={1,2,3,4,5}; std::vector<int> vec(a,a+sizeof(a)/sizeof(int)); I also know this way std::vector<int> vec(5,0); meaning vec has five elements and they are all initialized as 0. But these two ways are not related. How to explain the first one. What is the best way (what most people use) to initialize a vector if we know the values.
Class std::vector has constructor that accepts a pair of input iterators
template <class InputIterator>
vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
And this declaration
std::vector<int> vec(a,a+sizeof(a)/sizeof(int));
includes a call of the constructor where a and a + sizeof(a)/sizeof(int) are two random access iterators because pointers have such category of iterators.
Here a and a + sizeof(a)/sizeof(int) are two pointers that specify a range of initializers taken from the array for the created object of type std::vector<int>.
Take into account that you could also use the constructor that accepts an initializer list. For example
std::vector<int> v { 1, 2, 3, 4, 5 };
This constructor is supported starting from the C++ 2011.
std::vector<int> a = {1,2,3,4,5};
works as of C++11.
See:
http://en.cppreference.com/w/cpp/language/list_initialization
Also you can use:
int a[5]={1,2,3,4,5};
std::vector<int> vec;
for(int i=0; i<5: i++) vec.push_back(a[i]);

Vector initialization using array

we can initialize a vector using array. suppose,
int a[]={1,2,3}
vector<int>x(a,a+3)
this is a way . My question is, what is a and a+3 here, are they pointer?
and someone could explain this:
for the above array
vector<int>x(a,&a[3])
also gives no error and do the same as above code. If we write a[3], it should be outside of the array? can someone tell me the inner mechanism?
Yes, a and a+3 are pointers. The plain a is an array that gets converted implicitly to a pointer at the drop of a hat.
The construct &a[3] is identical in meaning to a+3 for plain C arrays. Yes, a[3] is outside the array, but one-past is allowed to point to, if you don't dereference it.
A vector's range constructor looks like this:
template <class InputIterator>
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
It will construct elements in the range [first, last), meaning that the last element is not included. &a[3] points to an element outside the bounds of the array, similar to how std::end(a) will point one past the end of a. Compare it to:
std::vector<int> x(std::begin(a), std::end(a));
Also, *(a + 3) is equivalent to a[3].
int a[]={1,2,3}
vectorx(a,a+3)
a is an array so it is always pointing to its base address.
a+3 mean base address+(sizeof(int) *3)
suppose base address is 100
a=100;
a+3=106;
vectorx(a,&a[3])
Here &a[3] is equivalent to a+3

C array vs pointer : array is considered as a variable, array+0 is considered as a pointer?

I've made a container class in C++, and I have a constructor from iterators so I can write MyContainer<double> x(v.begin(), v.end()) where v is a std::vector<double>. I would like to be able to do the same with a c-array but :
double array[3] = {1., 2. , 3.};
MyContainer<double> x(array, array+3); // Doesn't work : no matching function for call to ‘MyContainer<double>::MyContainer(double [3], double*)’
MyContainer<double> x(array+0, array+3); // Work
What is the origin of the problem and how to solve it ?
Thank you very much.
Don't accept references to iterators, take them by value. It's trying to pass a reference to an array; the failing expression needs the array to decay to a pointer.
Presumably you have
template< typename Iter >
MyContainer( Iter const &first, Iter const &last );
but you need
template< typename Iter >
MyContainer( Iter first, Iter last );
Iterators need to be lightweight enough to pass by value; all the standard templates do so.
An array cannot be used as an iterator because it cannot be incremented. The storage is fixed. When you use an array in an expression like arr + 0 or pass it by value to a function, it is implicitly converted to a pointer to its first element. But that conversion doesn't happen when passing by reference.
The result of array+0 is a pointer, while array itself is not a pointer, it is an array. Your constructor does not have an overload that takes an array and a pointer, hence the compile fails.
The idiomatic way of dealing with the problem of making the beginning and the ending iterators from an array is using the begin(...) and end(...) functions:
MyContainer<double> x(std::begin(array), std::end(array));
The overload takes care of figuring out where the end of your array is, freeing you from the need to add array's length to the pointer.

How can a vector be used in this way?

Can someone explain this code please? how is it that the function bar accepts a reference to the first element of the vector?
jintArray arry;
std::vector<int> foo = GetIntegerArray(env, arry);
bar(&foo[0])
where the protoytpe of bar is
bar(int* array)
This is valid as long as the template type isn't bool. The C++ vector type specifies that the vector elements are consecutive in memory like that so that you can do exactly this.
The reason why it doesn't work with bool is due to template specialization. Where the bools are compressed down to a bitfield.
http://en.wikipedia.org/wiki/Vector_%28C%2B%2B%29#vector.3Cbool.3E_specialization
how is it that the function bar accepts a reference to the first element of the vector?
This seems to be the source of the confusion. The expression &foo[0] is not a reference to the first element, but rather a pointer. operator[] is overloaded in the vector class to obtain a reference (or const-reference), and applying & will obtain the address of the object.
Yes. Just make sure the vector is not empty, or &foo[0] would be an error. C++11 introduced the std::vector<T>::data() function that does not have this problem.
Also, returning a vector by value is usually not a good idea. You might want to use an output iterator or a vector reference parameter in GetIntegerArray, so you would call it like this:
std::vector<int> foo;
GetIntegerArray(env, arry, back_inserter(foo));
or
std::vector<int> foo;
GetIntegerArray(env, arry, foo);
When you use std::vector<int>, it is guaranteed that all the element are created in contiguous memory. As such, when you write &v[0] it returns the pointer to the first element, and from this you can go the next element by writing &v[0]+1, and so on.
By the way, if you want to traverse through all elements or a section of elements, then a better interface for bar would be this:
void bar(int *begin, int *end)
{
for ( ; begin != end; ++begin)
{
//code
}
}
So you can call like this:
bar(&foo[0], &foo[0] + foo.size());//process all elements
bar(&foo[0], &foo[0] + foo.size()/2);//process first half elements
bar(&foo[0], &foo[0] + N); //process first N elements(assumingN <=foo.size())
bar(&foo[0]+foo.size()/2, &foo[0]+foo.size());//process second half elements

a question about vector in c++

I read some code written in c++ as following:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main() {
int iarr[] = {30, 12, 55, 31, 98, 11, 41, 80, 66, 21};
vector<int> ivector(iarr, iarr + 10);
}
in the above code, I pass iarr and iarr+10 to ivector(iarr, iarr + 10) to create a new vector, is this a proper way to construct a vector? I checked the STL document, it is not mentioned there, is this allowed?
and also, array iarr contains 10 elements, should I use ivector(iarr, iarr+9)?
Yes, it is allowed and yes, you are doing it right.
You are calling this templated constructor:
template<class InputIterator>
vector(
InputIterator _First,
InputIterator _Last
);
The template parameter InputIterator is int* (this is the type of the expressions iarr and iarr + 10).
Since the documentation states that _Last must point to one element beyond the last in the range, the + 10 is also correct to copy all 10 elements in the array (iarr + 9 points to the last element, iarr + 10 points to one beyond the last element).
Simple helper for arrays:
template <typename T, size_t N>
size_t size(T(&)[N]) { return N; }
template <typename T, size_t N>
T* begin(T(&array)[N]) { return array; }
template <typename T, size_t N>
T* end(T(&array)[N]) { return array + N; }
Now you can write:
int main() {
int const arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
std::vector<int> vec(begin(arr), end(arr));
}
And not worry about the size of the array any longer, it'll be computed automatically.
Yes, that is a constructor of std::vector. It's this one:
template <class InputIterator>
vector ( InputIterator first, InputIterator last, const Allocator& = Allocator() );
It takes two iterators (in your case pointers), one to the beginning and another to the end of the sequence of elements that are to initialize the vector. The last parameter is optional, and you don't need it unless you're using custom allocators.
The iterator to the end should be one past the last element you want to include. So, if you want all elements from iarr[0] to iarr[9], you need to pass in iarr + 10.
It is allocating a vector using Iterators and the original iarr[] shown. There are ten elements and +10 is a proper iteration because it is one step past the end. That's how vectors work - it must point to one position past the end. It is copying the contents of the array into the vector. More clearly, it is using this template to create the vector:
template <class InputIterator> vector ( InputIterator first,
InputIterator last, const Allocator& = Allocator() );
Iteration constructor: Iterates
between first and last, setting a copy
of each of the sequence of elements as
the content of the container.
This code is indeed allowed, if you check for example the documentation here
template <class InputIterator>
vector ( InputIterator first, InputIterator last, const Allocator& = Allocator() );
The range specified by the arguments follow the usual convention [first, last[, so passing iarr+10 is correct if you want the whole array to be copied
Yes, this is allowed, and ivector will contain 10 elements. And no, it should not be 9 because the end iterator should be one step past the end. If you know what ranges are, that range would be represented by this range: [beginning, end). That is to say, include the first one, and go right up to but don't include the last one.
Because the STL (C++ standard library cough) is all templates, anything that supports the operators ++ and * (dereference operator) can be passed as iterators to the vector constructor. This property amazingly makes the same code work for both pointers and vector iterators. Standard library design at its best.
Yes, last line in function main() calls constructor of std::vector. Have a look here
to see all vector constructor overloads. The third one is used here. Its parameters are iterators for template type (template argument used here is int and so iterator is of type int*). Second argument is iterator that points to the first sequence element that will not be copied into vector.