I am inserting elements with push_back in a vector. I want to read the data in FIFO and using iterator assigned to begin of vector. Is there any other approach of reading data in FIFO in a vector?
You may use a std::deque() and its pop_front() method.
You can access the elements of a vecotr just like you would access the elements of an array:
std::vector<std::string> vec;
// Excluded: push items onto vec
for (int i = 0; i < vec.size(); ++i) {
// Example:
std::cout << vec[i];
}
The code would be:
auto value = myvector[0];
myvector.erase(myvector.begin());
However, removing elements from the beginning (or somewhere in between) is slow, because it must copy the whole array. Access is fast though: vector allows random access (i.e. access by any explicit index) in O(1) (i.e. constant access time, i.e. very fast).
But another container structure instead of vector might make more sense for you, e.g. list or deque. Some STL implementations (or other framework) also have something like rope which is in many cases the best of both worlds.
There's nothing special to pay attention to. To insert, use
push_back, to extract, you need something like:
if ( !fifo.empty() ) {
ValueType results = fifo.front();
fifo.erase( fifo.begin() );
}
(Don't forget to check for empty before trying to remove an
element.)
An important point to remember is that both push_back and
in some cases erase can invalidate iterators, so you don't
want to keep iterators into the underlying vector hanging
around.
Related
I am trying to do a double loop across a std::vector to explore all combinations of items in the vector. If the result is good, I add it to the vector for another pass. This is being used for an association rule problem but I made a smaller demonstration for this question. It seems as though when I push_back it will sometimes change the vector such that the original iterator no longer works. For example:
std::vector<int> nums{1,2,3,4,5};
auto nextStart = nums.begin();
while (nextStart != nums.end()){
auto currentStart = nextStart;
auto currentEnd = nums.end();
nextStart = currentEnd;
for (auto a = currentStart; a!= currentEnd-1; a++){
for (auto b = currentStart+1; b != currentEnd; b++){
auto sum = (*a) + (*b);
if (sum < 10) nums.push_back(sum);
}
}
}
On some iterations, currentStart points to a location that is outside the array and provides garbage data. What is causing this and what is the best way to avoid this situation? I know that modifying something you iterate over is an invitation for trouble...
nums.push_back(sum);
push_back invalidates all existing iterators to the vector if push_back ends up reallocating the vector.
That's just how the vector works. Initially some additional space gets reserved for the vector's growth. Vector's internal buffer that holds its contents has some extra room to spare, but when it is full the next call to push_back allocates a bigger buffer to the vector's contents, moves the contents of the existing buffer, then deletes the existing buffer.
The shown code creates and uses iterators for the vector, but any call to push_back will invalidate the whole lot, and the next invalidated vector dereference results in undefined behavior.
You have two basic options:
Replace the vector with some other container that does not invalidate its existing iterators, when additional values get added to the iterator
Reimplement the entire logic using vector indexes instead of iterators.
int main() {
std::vector<std::vector<int>> v;
v.push_back({1,2,3,4});
auto it = v.at(0).begin();
int size = v.at(0).size();
std::cout<<size<<std::endl;
for (int i = 0; i < size; ++it)
{
v.push_back({5,6,7,8});
//std::cout<<*it<<std::endl;
}
return 0;
}
The iterator is broken when I push some elements into the outer container.
what should I do if I really want to iterate the container element inside of outer container and at the same time keep pushing back some new elements ? Many thanks!
When the outer vector resizes, it must do one of two things:
copy the elements
move the elements
It can only move the elements if the type has nonthrowing move semantics (the move constructor is marked noexcept, etc).
In this case, the element is a vector holding integers, which recursively depends on its elements. Since integer does not throw, the inner vector should be noexcept-movable too. The standard requires the iterators to remain valid when moving such a vector.
You say iterator is broken in your example, but the real problem is a bug in your code:
for (int i = 0; i < size; ++it) // << HERE
{
v.push_back({5,6,7,8});
//std::cout<<*it<<std::endl;
}
You don't increment the loop variable, you increment the iterator, in an infinite loop
what should I do if I really want to iterate the container element inside of outer container and at the same time keep pushing back some new elements ?
I see 3 possible solutions:
use container that does not relocate elements when new ones are added, for example std::map<size_t,std::vector<int>>, you should be aware of different memory usage and access speed
use index of inner array instead of iterator
add data to a temporary vector in the loop and after you done append all data to the original vector
Okay, so i'm doing this game like a project where i have 3 different objects.
void Character::shoot(){
Shot* s = new Shot(blablabla);
shots.push_back(s);
}
This happens dynamically, and currently i dont delete the pointers so it has to be loads of pointers to shots in that vector after a little while.
I use Bot, Character and Shot, and as i said i need help with storing and removing a pointer to the shot dynamically, preferably from a vector. I've got it to work like i put all the shot objects in a vector, but they never disappear from there. And i want to delete them permanently from my program when they collide with something, or reaches outside my screen width.
You can use std::remove and std::erase on any std container to remove content:
Shot* to_be_removed = ...;
std::vector<Shot*>::iterator i = std::remove(shots.begin(),shots.end(),to_be_removed);
std::erase(i,shots.end());
delete (to_be_removed);//don't forget to delete the pointer
This works when you know the element you want to remove. If you don't know the element you must find a way to identify the elements you want removed. Also if you have a system to identify the element it could be easier to use the container iterator in order to do the removal:
std::vector<Shot*>::iterator i = ...;//iterator the the element you want to remove
delete (*i);//delete memory
shots.erase(i);//remove it from vector
Lastly if you want to remove all pointers from the container and delete all the items at the same time you can use std::for_each
//c++ 03 standard:
void functor(Shot* s)
{
delete(s);
}
std::for_each(shots.begin(),shots.end(),functor);
shots.clear();//empty the list
//or c++11 standard:
std::for_each(shots.begin(),shots.end(),[] (Shot * s){ delete(s); } );
//the rest is the same
Using simple vector methods
You can iterate trough std::vector and use erase() method to remove current shot:
std::vector<cls*> shots; // Your vector of shots
std::vector<cls*>::iterator current_shot = shots.begin(); // Your shot to be deleted
while( current_shot < shots.end()){
if((*current_shot)->needs_to_be_deleted()){
// Remove item from vector
delete *current_shot;
current_shot = shots.erase(current_shot);
} else {
(*current_shot)->draw();
++current_shot; // Iterate trough vector
}
}
erase() returns iterator to next element after removed element so while loop is used.
Setting values to null and calling std::remove()
Note that std::vector::erase() reorganize everything after delete items:
Because vectors use an array as their underlying storage, erasing
elements in positions other than the vector end causes the container
to relocate all the elements after the segment erased to their new
positions. This is generally an inefficient operation compared to the
one performed for the same operation by other kinds of sequence
containers (such as list or forward_list).
This way you may end up with O(n^2) complexity so you may rather set values to null and use std::remove() as suggested by juanchopanza in comment, Erase-Remove idiom:
int deleted = 0;
for( current_shot = shots.begin(); current_shot < shots.end(); ++current_shot){
if((*current_shot)->needs_to_be_deleted()){
// Remove item from vector
delete *current_shot;
*current_shot = null;
++deleted;
}
}
if( deleted){
shots.erase( std::remove(shots.begin(), shots.end(), null));
}
Using std::list
If you need large amount of shot creations and deletions std::vector may not be the best structure for containing this kind of list (especially when you want to remove items from the middle):
Internally, vectors use a dynamically allocated array to store their
elements. This array may need to be reallocated in order to grow in
size when new elements are inserted, which implies allocating a new
array and moving all elements to it. This is a relatively expensive
task in terms of processing time, and thus, vectors do not reallocate
each time an element is added to the container.
See link from Raxvan's comment for performance comparison.
You may want to use std::list instead:
List containers are implemented as doubly-linked lists; Doubly linked
lists can store each of the elements they contain in different and
unrelated storage locations. The ordering is kept by the association
to each element of a link to the element preceding it and a link to
the element following it.
Compared to other base standard sequence containers (array, vector and
deque), lists perform generally better in inserting, extracting and
moving elements in any position within the container for which an
iterator has already been obtained, and therefore also in algorithms
that make intensive use of these, like sorting algorithms.
The main drawback of lists and forward_lists compared to these other
sequence containers is that they lack direct access to the elements by
their position;
Which is great for removing items from the middle of the "array".
As for removing, use delete and std::list::erase():
std::list<cls*> shots;
std::list<cls*>::iterator current_shot;
// You have to use iterators, not direct access
for( current_shot = shots.begin(); current_shot != shots.end(); current_shot++){
if( (*current_shots)->needs_to_be_deleted()){
delete *current_shot;
shots.erase(current_shot); // Remove element from list
}
}
Using std::shared_ptr
If you have more complex program structure and you use the same object on many places and you can simply determine whether you can delete object already or you need to keep it alive for a little bit more (and if you are using C++11), you can use std::shared_ptr (or use different kind of "smart pointers" which delete data where reference count reaches zero):
// Pushing items will have slightly more complicated syntax
std::list< std::shared_ptr<cls>> shots;
shots.push_back( std::shared_ptr( new cls()));
std::list< std::shared_ptr<cls>>::iterator current_shot;
// But you may skip using delete
shots.erase(current_shot); // shared_ptr will take care of freeing the memory
Simply use "delete" to deallocate the memory:
vector<Shot*>::iterator i;
for(i = shoot.begin(); i != shoot.end(); ++i)
{
delete (*i);//delete data that was pointed
*i = 0;
}
shoot.clear();
This will delete all elements from the heap and clear your vector.
static std::map <unsigned int, CPCSteps> bestKvariables;
inline void copyKBestVar(MaxMinVarMap& vMaxMinAll, size_t& K, std::vector<unsigned int>& temp)
{
// copy top k variables and store in a vector.
MaxMinVarMap::reverse_iterator iter1;
size_t count;
for (iter1 = vMaxMinAll.rbegin(), count = 0; iter1 != vMaxMinAll.rend()&& count <= K; ++iter1, ++count)
{
temp.push_back(iter1->second);
}
}
void myAlgo::phase1(unsigned int& vTarget)
{
CPCSteps KBestForT; // To store kbest variables for only target variable finally put in a global storage
KBestForT.reserve(numVars);
std::vector<unsigned int> tempKbest;
tempKbest.reserve(numVars);
.......
.......
copyKBestVar(mapMinAssoc, KBestSize, tempKbest); // Store k top variables as a k best for this CPC variable for each step
KBestForT.push_back(tempKbest);
.....
.....
bestKvariables.insert(make_pair(vTarget, KBestForT)); // Store k best in a Map
.....
....
}
The Problem: Map "bestKvariables" is not overwriting the first element, but it keeps updating the rest of the elements. I tried to debug it but the problem i found is in insert command.
Thanks in advance for helping.
Another Question: whether i can reserve the size of a map(like vector.reserve(..)) in the beginning to avoid the insertion cost.
Sorry for providing insufficient information.
I means if there are four vTarget variables 1, 2, 3, 4. I do some statistical calculations for each variable.
There are more than one iterations for these variables, i would like to store top k results of each variable in a map to use it next iteration.
I saw the first inserted variable(with key unsigned int "vTarget") is not updated on further iterations(it remains the value inserted on first iteration).
But the other variables (keys inserted after the first) are remains updated.
Another Question: whether i can reserve the size of a map(like vector.reserve(..)) in the beginning to avoid the insertion cost.
std::map does not have a reserve() function unlike std::vector.
Usually, the Standard library provides functions for containers that provide and ensure good performance or provide a means to achieve the same.
For a container like std::vector reallocation of its storage can be a very costly
operation. A simple call to push_back() can lead to every element in the std::vector to be copied to a newly allocated block of memory. A call to reserve() can avoid these unnecessary allocations and copy operations for std::vector and hence the same is provided for it.
std::map never needs to copy all of the existing/remaining elements simply because a new element was inserted or removed. Hence it does not provide any such function.
Though the Standard does not specify how a std::map should be implemented the behavior expected and the complexity desired ensures that most implementations implement it as a tree, unlike std::vector which needs elements to be allocated in contiguous memory locations.
map::insert isn't supposed to update/overwrite anything, just insert not-yet-present elements. Use operator[] for updating, it also inserts elements when the specified key is not present yet.
I ran into this problem when I tried to write out an new algorithm to reorder elements in std::vector. The basic idea is that I have std::list of pointters pointing into std::vector in such way that *list.begin() == vector[0], *(++list.begin()) == vector[1] and so on.
However, any modifications on list's element positions breaks the mapping. (Including appended pointers) When the mapping is broken the list's elements can be in random order but they point still into correct elements on vector. The task would be to reorder the elements in vector to correct the mapping.
Simplest method to do it (How I have done it now):
create new empty std::vector and resize it to equal size of the old vector.
iterate through the list and read elements from the old vector and write them into new vector. Set the pointer to point into new vector's element.
swap vectors and release the old vector.
Sadly the method is only useful when I need more capacity on the vector. It's inefficient when the current vector holding the elements has enough capacity to store all incoming elements. Appended pointers on the list will point into diffrent vector's storgate. The simple method works for this because it only reads from the pointers.
So I would want to reorder the vector "in place" using constant amount of memory. Any pointer that was not pointing into current vector's storgate are moved to point into current vector's storgate. Elements are simple structures. (PODs)
I'll try post an example code when I have time..
What should I do to achieve this? I have the basic idea done, but I'm not sure if it is even possible to do the reordering with constant amount of memory.
PS: I'm sorry for the (possibly) bad grammar and typos in the post. I hope it's still readable. :)
First off, why do you have a list of pointers? You might as well keep indices into the vector, which you can compute as std::distance(&v[0], *list_iter). So, let's build a vector of indices first, but you can easily adapt that to use your list directly:
std::vector<T> v; // your data
std::list<T*> perm_list; // your given permutation list
std::vector<size_t> perms;
perms.reserve(v.size());
for (std::list<T*>::const_iterator it = perm_list.begin(), end = perm_list.end(); it != end; ++it)
{
perms.push_back(std::distance(&v[0], *it));
}
(There's probably a way to use std::transform and std::bind, or lambdas, to do this in one line.)
Now to do the work. We simply use the cycle-decomposition of the permutation, and we modify the perms vector as we go along:
std::set<size_t> done;
for (size_t i = 0; i < perms.size(); while(done.count(++i)) {})
{
T tmp1 = v[i];
for (size_t j = perms[i]; j != i; j = perms[j])
{
T tmp2 = v[j];
v[j] = tmp1;
tmp1 = tmp2;
done.insert(j);
}
v[i] = tmp1;
}
I'm using the auxiliary set done to track which indices have already been permuted. In C++0x you would add std::move everywhere to make this work with movable containers.