Initializing and setting a vector<int> - c++

vector<int> v;
v.push_back(0); //you have to do this
//v[0] = 0; //this gives you an error
v[0] = 1000000; //but now you can set it
So, how come the first time you initialize a vector, you have to push_back, and after that you can just set it? For a primitive type, say int, you can do int i = 0; for initialization.

If you know in advance the size of your vector, definitively don't use a plain sequence of push_back()'s, since it may be a waste of time reallocating if your vector is large (say, >512 elements).
Better do:
OPTION 1: Preallocating and pushing
vector<int> v;
v.reserve(N); // N is the expected size, but right now [0] is undefined.
for (...) {
v.push_back(...); // No problems in adding more than N elements, but may have to reallocate.
}
OPTION 2: Resizing and filling
vector<int> v;
v.resize(N);
for (size_t i=0;i<N;i++)
v[i] = ...; // You can't write past N-1 here!
OPTION 3: Create directly with the correct size, then fill
vector<int> v(N);
for (size_t i=0;i<N;i++)
v[i] = ...; // You can't write past N-1 here!
OPTION 4: Create a vector with the correct size and initialized to some fixed value
vector<int> v(N,val); // v[0:N-1] are all equal to val

Because when you first create a vector it is empty so vector[0] doesn't exist. push_back adds an element to the vector then you can modify or read it with vector[i]

Just to make everything 100% clear, your declaration of a vector,
vector<int> v;
is in some sense similar to the declaration of a variable:
int x;
and if you then want, say,
cout << x;
you will get rubbish. Though, if you declare
int x(2);
everything will be fine. Similarly for vectors: declaration of
vector<int> v;
allocates some memory space for a vector, but not fills it. You can then specify
vector<int> v(2);
which means that you now have declared a vector of two elements, or go for a vector-only feature - push_back. This would add elements to your vector, as you've noticed.

Because std::vector<int> isn't std::map<int, int>.
std::vector requires you to manually push_back() or (in C++11) emplace_back() elements for them to be included in the collection. And of course some of its constructors allows you to include initial elements to it. And of course again its assignment operators.
The subscript([]) operator should only be used in reading and/or modifying existing elements. Indexing using operator[] out-of-bounds (non-existent) elements would result in undefined behavior.

You can't access v[0] because there is no v[0] yet. The vector starts off default-constructed as an empty vector. You push an element onto the back and it grows in size by 1. You're then able to access the element you just added. If you want it to start off with one element, use the appropriate constructor:
std::vector<int> v(1); //one zeroed integer
You're comparing apples and oranges. int i = 0; would be like std::vector<int> v;.

You should first allocate memory for setting element values, such as
v.resize(new_size);
or use push_back method to add elements.

Related

Why can't we input a vector as we input an array in C++?

The wiki says:
The elements of a vector are stored contiguously. AND
Vectors allow random access; that is, an element of a vector may be referenced in the same manner as elements of arrays (by array indices).
So why can't we input the elements of a vector as:
vector<int> v;
for(int i=0;i<3;i++)
{
cin>>v[i];
}
Either you need to resize the vector upfront - as other answers say - or you can use C++ standard library. Then the equivalent of your for loop is the following one line:
copy_n(istream_iterator<int>(cin), 3, back_inserter(v));
and it takes care of allocation/resizing.
Your vector has zero elements right now. Try allocating it some space as:
vector<int> v(5);
Then your method would work.
The problem is that you need to allocate the elements of the vector first. So try vector<int> v(4);, so it will start with 4 elements. Then you can load values into them.

Change from static array to vector

here's my code:
vector<int> Edge[1000000]; //size of array must be very high
scanf("%d%d",&N,&M );
//N = size of workable index numbers for Edge
for( i=1;i<=M;i++){
scanf("%d%d",&u,&v );
Edge[u].push_back( v );
}
But as you can see, it's a static array of vectors.
If i change it to this:
vector<vector<int>> Edge;
How can i do that for cycle and pushback? I need to create a vector of N+1 size and each position is also a vector.
I need to create a vector of N+1 size and each position is also a vector.
Considering that you know the size of the external container at compile time, you can also use std::array to store the vectors:
std::array<std::vector<int>, N + 1> Edge;
If you don't know the size at compile time, you could use:
std::vector<std::vector<int>> Edge;
but as a general rule of thumb, tend to avoid vectors of vectors, as they don't usually work nicely.
You can construct vectors of a given size by passing an int to their constructor. Then afterwards you can use a loop to initialize the subvectors.
int size;
vector<vector<int>> Edge(size); //Initializes Outer Array to have 'size' elements
for(auto i:Edge)
{
// i is a vector within Edge
}
The advantage is that you don't have to push back. If you still wanted to push_back in order (not have to track an iterator/int) you could use vector.reserve() instead.

Resizing std::vector without destroying elements

I am using all the time the same std::vector<int> in order to try to avoid allocating an deallocating all the time. In a few lines, my code is as follows:
std::vector<int> myVector;
myVector.reserve(4);
for (int i = 0; i < 100; ++i) {
fillVector(myVector);
//use of myVector
//....
myVector.resize(0);
}
In each for iteration, myVector will be filled with up to 4 elements. In order to make efficient code, I want to use always myVector. However, in myVector.resize() the elements in myVector are being destroyed. I understand that myVector.clear() will have the same effect.
I think if I could just overwrite the existing elements in myVector I could save some time. However I think the std::vector is not capable of doing this.
Is there any way of doing this? Does it make sense to create a home-grown implementation which overwrites elements ?
Your code is already valid (myVector.clear() has better style than myVector.resize(0) though).
'int destructor' does nothing.
So resize(0) just sets the size to 0, capacity is untouched.
Simply don't keep resizing myVector. Instead, initialise it with 4 elements (with std::vector<int> myVector(4)) and just assign to the elements instead (e.g. myVector[0] = 5).
However, if it's always going to be fixed size, then you might prefer to use a std::array<int, 4>.
Resizing a vector to 0 will not reduce its capacity and, since your element type is int, there are no destructors to run:
#include <iostream>
#include <vector>
int main() {
std::vector<int> v{1,2,3};
std::cout << v.capacity() << ' ';
v.resize(0);
std::cout << v.capacity() << '\n';
}
// Output: 3 3
Therefore, your code already performs mostly optimally; the only further optimisation you could make would be to avoid the resize entirely, thereby losing the internal "set size to 0" inside std::vector that likely comes down to an if statement and a data member value change.
std::vector is not a solution in this case. You don't want to resize/clear/(de)allocate all over again? Don't.
fillVector() fills 'vector' with number of elements known in each iteration.
Vector is internally represented as continuous block of memory of type T*.
You don't want to (de)allocate memory each time.
Ok. Use simple struct:
struct upTo4ElemVectorOfInts
{
int data[4];
size_t elems_num;
};
And modify fillVector() to save additional info:
void fillVector(upTo4ElemVectorOfInts& vec)
{
//fill vec.data with values
vec.elems_num = filled_num; //save how many values was filled in this iteration
}
Use it in the very same way:
upTo4ElemVectorOfInts myVector;
for (int i = 0; i < 100; ++i)
{
fillVector(myVector);
//use of myVector:
//- myVector.data contains data (it's equivalent of std::vector<>::data())
//- myVector.elems_num will tell you how many numbers you should care about
//nothing needs to be resized/cleared
}
Additional Note:
If you want more general solution (to operate on any type or size), you can, of course, use templates:
template <class T, size_t Size>
struct upToSizeElemVectorOfTs
{
T data[Size];
size_t elems_num;
};
and adjust fillVector() to accept template instead of known type.
This solution is probably the fastest one. You can think: "Hey, and if I want to fill up to 100 elements? 1000? 10000? What then? 10000-elem array will consume a lot of storage!".
It would consume anyway. Vector is resizing itself automatically and this reallocs are out of your control and thus can be very inefficient. If your array is reasonably small and you can predict max required size, always use fixed-size storage created on local stack. It's faster, more efficient and simpler. Of course this won't work for arrays of 1.000.000 elements (you would get Stack Overflow in this case).
In fact what you have at present is
for (int i = 0; i < 100; ++i) {
myVector.reserve(4);
//use of myVector
//....
myVector.resize(0);
}
I do not see any sense in that code.
Of course it would be better to use myVector.clear() instead of myVector.resize(0);
If you always overwrite exactly 4 elements of the vector inside the loop then you could use
std::vector<int> myVector( 4 );
instead of
std::vector<int> myVector;
myVector.reserve(4);
provided that function fillVector(myVector); uses the subscript operator to access these 4 elements of the vector instead of member function push_back
Otherwise use clear as it was early suggested.

C++ Regarding assigning value to Vector<Point> myVariable

C++ Regarding assigning value to Vector myVariable
Hi guys.
I have this struct
struct Point
{
int x,y;
}
and in my main.cpp i got something like this
int main()
{
vector<Point> myPoints;
myPoints[0].x = 1;
myPoints[0].y = 1;
myPoints[1].x = 2;
myPoints[1].x = 2;
return 0;
}
and i get segmentation core dump, what is wrong with setting value to the element of the vector.
Thanks for guiding!
vector<Point> myPoints;
creates an empty vector of Point objects. Since it's empty, you can't access myPoint[0], myPoint[1] etc. Attempting to do this won't auto-create elements; instead, it will invoke undefined behaviour – quite typically a segmentation fault.
Use push_back to append elements to the vector:
myPoints.push_back(Point(1,1));
or, alternatively, resize the vector so it contains default-constructed elements:
myPoints.resize(2);
You can also use an argument to the constructor of std::vector to resize it right at initialization time:
vector<Point> myPoints(2); // auto-resizes the vector to length 2
Note about push_back. In C++11, you may use emplace_back() instead of push_back() as well: myPoints.emplace_back(1,1); appends a new element to the vector by calling the Point constructor in-place, using 1,1 as the arguments to the constructor. This is the most efficient way of appending newly created elements to the vector.
You didn't initialize any objects. You need to make the objects and then put them into the vector, otherwise you are acting on something that does not exist, which is causing the segfault.
Example:
Point myPoint;
myPoints.push_back(myPoint);
myPoints[0].x = 1;
The problem is that you are trying to access elements which have not been created yet.
After this line:
vector myPoints;
you have a vector myPoints which has exactly 0 elements. Thus, myPoints[0] is meaningless.
You need to do one of the following:
Create a vector with a pre-determined size: vector<Point> myPoints(2); (note: you can expand or shrink it later), then execute myPoints[0].x=1 etc.
Use the vector's push_back method to add new elements to the vector, i.e. myPoints.push_back(Point(0, 0));
After you declare the new vector object, use the resize method to allocate space for two new elements.

assigning vector

how I can assign v[i] to an series of integers ( type of v is vector ) without initially filling inside
Do you mean initializing std::vector to a series of integers?
int i[] = {1, 2, 3, 4, 5};
std::vector<int> myVector(i, i+ (sizeof(i)/sizeof(int)));
If you meant to create a vector of some elements so you can perform the assignment using their index values. Here, the following statement declares and initializes a vector with its elements being default initialized to 0.
std::vector<int> myVector(5); // constructs a vector of size five integers.
for (int x = 0; x < 5; x++)
myVector[x] = i[x]; // assign values using subscript [..]
But I think the even better way to go would be as #CashCow mentioned in his answer.
Also, note that you can also pre-allocate memory to add elements into the vector with avoiding any repeated memory allocations.
For example:
std::vector<int> myVector; // empty vector for integers
myVector.reserve(5); // pre-allocates memory for five integers
for (int i = 0; i < 5; i++) // now, you can add your elements
myVector.push_back(i);
It is usually a good idea to pre-allocate memory if you know the size of elements i.e in case of large number of elements when the performance is an important factor.
If you have anything that has the traits of an iterator you can use vector's assign method:
std::vector<int> v;
v.assign( iterStart, iterEnd );
iterStart should be such that *iterStart is the first value you want to add.
iterEnd should be one past the end, it is a terminating condition
++iter would move you to the next iterator in the input series.
I don't know what you mean by assign v[i] though. You cannot assign an element to a series. If you want to write the series at a location into an existing vector you can use insert instead of assign.
common way of adding items is calling std::vector<>push_back() method.
std::vector<int> myVector;
myVector.push_back(5);
myVector.push_back(10);
myVector.push_back(3);