I have a question about std::vector -
vector<int> vec(1,0);
while(//something_1)
{
while(//something_2)
{
...
vec.pushback(var)
...
}
process(vec.size()); //every iteration- different size
vec.clear();
vec.resize(0,0);
}
On this case - every vec.push_back(var) there is reallocation of a new array with size bigger by one than the former array.
My question is - if there is a way using one vector, so after the inner while(//something_2), the vec.push_back(var) command will push back from the first cell of vec? instead of using vec.clear() and vec.resize(0,0)? so I could save the resize part and the reallocation.
The size of the vector is important for the function process(vec.size())
Thanks.
You can use reserve first time if you know beforehand approximately how much your vector could grow.
clear Leaves the capacity() of the vector unchanged. Which means that push_back & and other modifiers will use the same memory.
resize(0,0) should be removed.
Related
What will happen if I expand a container while iterating through it, may I meet the new elements or just the old ones
std::vector<int> arr(0);
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
for (auto& ele : arr) {
if (4 == ele) std::cout << "meet new eles" << endl;
arr.push_back(4);
}
push_back may invalidate any iterator to the vector, what you have there is undefined behaviour.
std::vector internally allocates an array with its elements stored contiguously in memory. To do so it needs to preallocate an estimate of the size it may need, that's known as the capacity of the vector. At push_back if the capacity is reached it allocates a new bigger array, copies/moves all the contents of the previous array to the new one and then deletes the old one. That invalidates the iterators, that keep pointing to a deleted array.
Also worth mentioning that the allocation of the new array adds a considerable performance hit. If you know the size that your vector will have always use reserve() to preallocate memory.
Now, true is that if you reserve capacity before hand and never push back exceeding that capacity the iterators won't be invalidated (only the past-end iterator) and you can keep incrementing them since they point to an array of contiguous elements. But I wouldn't advice to do so, IMO the risk of reallocating the vector by mistake is not worth it.
If you are guaranteed to never remove elements the simplest solution would still be to use a regular for loop.
for(size_t i=0, n=arr.size(); i<n; ++i)
{
if(/* something */)
{
arr.push_back(/* ... */);
++n;
}
}
I know it's a trivial solution, but others maybe searching and will find this question.
Good note from #Long_GM. This will not work on every container. std::map for example cannot be iterated in this manner whether or not you insert any values.
I'd like to fill a vector with a (known at runtime) quantity of data, but the elements arrive in (index, value) pairs rather than in the original order. These indices are guaranteed to be unique (each index from 0 to n-1 appears exactly once) so I'd like to store them as follows:
vector<Foo> myVector;
myVector.reserve(n); //total size of data is known
myVector[i_0] = v_0; //data v_0 goes at index i_0 (not necessarily 0)
...
myVector[i_n_minus_1] = v_n_minus_1;
This seems to work fine for the most part; at the end of the code, all n elements are in their proper places in the vector. However, some of the vector functions don't quite work as intended:
...
cout << myVector.size(); //prints 0, not n!
It's important to me that functions like size() still work--I may want to check for example, if all the elements were actually inserted successfully by checking if size() == n. Am I initializing the vector wrong, and if so, how should I approach this otherwise?
myVector.reserve(n) just tells the vector to allocate enough storage for n elements, so that when you push_back new elements into the vector, the vector won't have to continually reallocate more storage -- it may have to do this more than once, because it doesn't know in advance how many elements you will insert. In other words you're helping out the vector implementation by telling it something it wouldn't otherwise know, and allowing it to be more efficient.
But reserve doesn't actually make the vector be n long. The vector is empty, and in fact statements like myVector[0] = something are illegal, because the vector is of size 0: on my implementation I get an assertion failure, "vector subscript out of range". This is on Visual C++ 2012, but I think that gcc is similar.
To create a vector of the required length simply do
vector<Foo> myVector(n);
and forget about the reserve.
(As noted in the comment you an also call resize to set the vector size, but in your case it's simpler to pass the size as the constructor parameter.)
You need to call myVector.resize(n) to set (change) the size of the vector. calling reserve doesn't actually resize the vector, it just makes it so you can later resize without reallocating memory. Writing past the end of the vector (as you are doing here -- the vector size is still 0 when you write to it) is undefined behavior.
When I call std::vector::reserve when the identifier is of type std::vector<Foo*> reserve(...) does nothing:
std::vector<int*> bar;
bar.reserve(20);
//I expect bar.size to return 20...
std::size_t sz = bar.size();
for(std::size_t i = 0; i < sz; ++i) {
//Do Stuff to all items!
}
The aforementioned for loop runs exactly zero times and bar.size() returns zero. I do not remember if this is also true for all other STL containers, but if so, including the behavior for std::vector: WHY?
.reserve() doesn't change the size of a vector. The member function you are looking for is .resize(). reserve() is simply an optimization. If you are going to add a bunch of things to a vector one-by-one using push_back() then telling it how many you will add using reserve() can make the code run a little bit faster. But just calling reserve() doesn't change the size.
vector::reserve() changes the capacity of a vector, not its size.
capacity is how much memory has been allocated internally to hold elements of the vector. size is how many elements have actually held by the vector. vector::resize() affects the latter.
reserve changes the capacity of the vector, not the size. You probably want resize
i have a project in c++03 that have a problem with data structure: i use vector instead of list even if i have to continuously pop_front-push_back. but for now it is ok because i need to rewrite too many code for now.
my approach is tuo have a buffer of last frame_size point always updated. so each frame i have to pop front and push back. (mayebe there is a name for this approach?)
so i use this code:
Point apoint; // allocate new point
apoint.x = xx;
apoint.y = yy;
int size = points.size()
if (size > frame_size) {
this->points.erase( points.begin() ); // pop_front
}
this->points.push_back(apoint);
i have some ready-to-use code for an object pool and so i thought: it is not a great optimization but i can store the front in the pool and so i can gain the allocation time of apoint.
ok this is not so useful and probably it make no sense but i ask just to educational curiosity: how can i do that?
how can i store the memory of erased element of a vector for reusing it? does this question make sense? if not, why?
.. because erase does not return the erased vector, it return:
A random access iterator pointing to the new location of the element
that followed the last element erased by the function call, which is
the vector end if the operation erased the last element in the
sequence.
i have some ready-to-use code for an object pool ... how can i do that?
Using a vector, you can't. A vector stores its elements in a contiguous array, so they can't be allocated one at a time, only in blocks of arbitrary size. Therefore, you can't use an object pool as an allocator for std::vector.
how can i store the memory of erased element of a vector for reusing it? does this question make sense? if not, why?
The vector already does that. Your call to erase moves all the elements down into the space vacated by the first element, leaving an empty space at the end to push the new element into.
As long as you use a vector, you can't avoid moving all the elements when you erase the first; if that is too inefficient, then use a deque (or possibly a list) instead.
I'm not sure to understand what you want to do, but this should be functionnally equivalent to what you wrote, without constructing a temporary Point instance:
// don't do this on an empty vector
assert (points.size() > 0);
// rotate elements in the vector, erasing the first element
// and duplicating the last one
copy (points.begin()+1, points.end(), points.begin());
// overwrite the last element with your new data
points.back().x = xx;
points.back().y = yy;
EDIT: As Mike Seymour noted in the comments, neither this solution nor the approach proposed in the question cause any new memory allocation.
The resize() function makes vector contain the required number of elements. If we require less elements than vector already contain, the last ones will be deleted. If we ask vector to grow, it will enlarge its size and fill the newly created elements with zeroes.
vector<int> v(20);
for(int i = 0; i < 20; i++) {
v[i] = i+1;
}
v.resize(25);
for(int i = 20; i < 25; i++) {
v[i] = i*2;
}
But if we use push_back() after resize(), it will add elements AFTER the newly allocated size, but not INTO it. In the example above the size of the resulting vector is 25, while if we use push_back() in a second loop, it would be 30.
vector<int> v(20);
for(int i = 0; i < 20; i++) {
v[i] = i+1;
}
v.resize(25);
for(int i = 20; i < 25; i++) {
v.push_back(i*2); // Writes to elements with indices [25..30), not [20..25) ! <
}
Then where is the advantage of resize() function ? Doesn't it creates a confusion for indexing and accessing elements from the vector ?
It sounds as though you should be using vector::reserve.
vector::resize is used to initialize the newly created space with a given value (or just the default.) The second parameter to the function is the initialization value to use.
Remember the alternative - reserve. resize is used when you want to act on the vector using the [] operator -- hence you need a "empty" table of elements. resize is not intended to be used with push_back. Use reserve if you want to prepare the array for push_back.
Resize is mainly usefull if the array has meaningful "empty" constructor, when you can create an array of empty elements, and only change the ones that are meaningful.
The resize() method changes the vector's size, which is not the same as the vector's capacity.
It is very important to understand the distinction between these two values:
The size is the number of actual elements that the vector contains.
The capacity is the maximum number of elements that the vector could contain without reallocating a larger chunk of memory.
A vector's capacity is always larger or equal to its size. A vector's capacity never shrinks, even when you reduce its size, with one exception: when you use swap() to exchange the contents with another vector. And as others have mentioned, you can increase a vector's capacity by calling reserve().
I think that using the correct terminology for size and capacity makes it easier to understand the C++ vector class and to speak clearly about its behavior.
resize() function changes the actual content of the vector by inserting or erasing elements from the vector. It does not only change its storage capacity. To direct a change only in storage capacity, use vector::reserve instead. Have a look at the vector visualization in the link, notice where v.back is pointing to.
I don't really understand the confusion. The advantage of resize is that it resizes your vector. Having to do a loop of push_backs is both tedious and may require more than one "actual" resize.
If you want to "resize" your vector without changing its accessible indexes then use std::vector<T>::reserve. That will change the size of the internal allocated array without actually "adding" anything.