I have the following problem:
vector<CPerson>toRemove;// has some objects that are contained in m_vObjects
vector<CPerson>m_vObjects;
for (auto it = toRemove.begin(); it != toRemove.end(); ++it)
{
for (auto iter = m_vObjects.begin(); iter != m_vObjects.end(); ++iter)
{
iter = m_vObjects.erase(it);
}
}
What I want to do is delete all the objects from m_vObjects that are contained in toRemove. I have tried a lot of stuff, but nothing worked fine.
Your code is wrong: you cannot use iterator from one container to remove items from the other container. One way to achieve what you want is to use std::set_difference (requires your arrays to be sorted):
vector<CPerson>toRemove;// has some objects that are contained in m_vObjects
vector<CPerson>m_vObjects;
vector<int> diff;
std::set_difference(
m_vObjects.begin(), m_vObjects.end(),
v2.begin(), v2.end(),
std::inserter(diff, diff.begin()));
m_objects = diff;
If it is not desired to sort arrays, then you can use std::remove:
for (const auto& element_to_remove : toRemove) {
std::remove (
m_vObjects.begin (),
m_vObjects.end (),
element_to_remove);
}
1) You cannot use iterator from toRemove in m_vObjects. They are strongly connected to each instance of collection.
2) It is not really a good practice to use loop on iterators while modifying collection: for example you have deleted an object after current interator, but he still thinks that object is there. If I'm correct, it causes undefined behavior.
3) The fix should be check equality of objects, that are pointed by iterators.
if( ( *it == *iter )
{
iter= vObjects.erase( iter );
}
But still, my solution works only if == is overloaded for person, or you have another method that checks equality. And it is very bad for performance. Actually, IMHO, such actions at vectors are always bad for performance, it's better to use set or map if you need to find something. And set has some in-build methods to intersect them.
Related
Since we now have advance() and the prev() to move iterator to go front or go back, and we already have begin() and end().
I wonder is there any situation we better/have to move reverse iterator back and front?
Algorithms often take two iterators that specify a range of elements. For example std::for_each:
std::vector<int> x;
std::for_each(x.begin(),x.end(),foo);
If you want to make for_each iterate in reverse order (note: for_each does iterate in order) then neither advance nor prev are of any help, but you can use reverse iterators:
std::for_each(x.rbegin(),x.rend(),foo);
Because using begin() and end() to iterate in reverse looks horrible:
std::vector<int> v {1, 2, 3};
if(!v.empty()) { //need to make sure of that before we decrement
for(auto it = std::prev(v.end()); ; --it) {
//do something with it
if(it == v.begin()) {
break;
}
}
}
Compare it with reverse iterator version:
std::vector<int> v {1, 2, 3};
for(auto it = v.rbegin(); it != v.rend(); it++) {
//do something with it
}
When you have a function template that takes iterators, and want it to operate on the data in reverse.
E.g.
std::string s = "Hello";
std::string r(s.rbegin(), s.rend());
std::cout << r;
When you use algorithms like std::for_each(), std::accumulate(), std::find_if()... they systematically progress with ++.
If you want this progression to physically occur backwards, then the reverse
iterators are useful.
I guess it is good practise because it seems odd if you start from end and finish in begin. You can easily say last but one by using rbegin.
vector::reverse_iterator itr1;
for (itr1 = vec.rbegin(); itr1 < vec.rend(); itr1++) {
if (*itr1 == num) {
vec.erase((itr1 + 1).base());
}
}
You can use as a function which deletes that Which num want to erase in vector
The need for rbegin()/rend() is because begin() is not the same as rend(), and end() is not rbegin(), see this image from cppreference
This way, you can use any algorithm going forward from beginning to end or backwards from the last to the first element.
There are examples with for each. However, more general, it allows you to reuse any algorithm or operators that works with iterators with advancing, to do the same thing but in a reverse order.
Let's say that I have vector of pairs, where each pair corresponds to indexes (row and column) of certain matrix I am working on
using namespace std;
vector<pair<int, int>> vec;
I wanted to, using auto, go through the whole vector and delete at once all the pairs that fulfill certain conditions, for example something like
for (auto& x : vec) {
if (x.first == x.second) {
vec.erase(x);
}
}
but it doesn't work, as I suppose vec.erase() should have an iterator as an argument and x is actually a pair that is an element of vector vec, not iterator. I tried to modify it in few ways, but I am not sure how going through container elements with auto exactly works and how can I fix this.
Can I easily modify the code above to make it work and to erase multiple elements of vector, while going through it with auto? Or I should modify my approach?
For now it's just a vector of pairs, but it will be much worse later on, so I would like to use auto for simplicity.
vector::erase() invalidates any outstanding iterators, including the one your range based for loop is using. Use std::remove_if():
vec.erase(
std::remove_if(
vec.begin(),
vec.end(),
[](const pair<int,int> &xx) { return xx.first == xx.second; }
), vec.end()
);
std::remove_if() swaps the elements to the end of the vector and then you can safely erase them.
I would prefer something like this:
pair<int, int> pair = nullptr;
auto iter = vec.begin();
while(iter != vec.end()){
pair = (*iter);
if(pair.first == pair.second){
iter = this->vec.erase(iter);
}else{
++iter;
}
}
Suppose you have an
std::unordered_set<std::shared_ptr<A>> as;
// (there is an std::hash<std::shared_ptr<A>> specialisation)
and you want to replace some of its elements while iterating over it:
for (auto it = as.begin(); it != as.end(); ++it) {
if ((*it)->condition()) {
as.erase(it);
as.insert(std::make_shared<A>(**it));
}
}
This could invalidate the iterator at erase and insert (if rehashing takes place), so this loop will exhibit undefined behaviour and will most likely crash horribly.
The one solution I can think of is using two separate vectors to buffer the insert and erase operations and later use the overloads that take iterator pairs for erasing and inserting (this is presumably more rehashing-friendly).
Even if I use the buffer approach, this still seems bloated code and could result in two rehashes that might possibly both be unnecessary.
So, is there a better way to do it?
I just thought of a possible approach (just after asking) but maybe there are even better ones.
Copying everything to a vector and then rebuilding the set from the vector should be faster:
std::vector<std::shared_ptr> buffer;
buffer.reserve(as.size());
for (auto it = as.begin(); it != as.end(); ++it) {
if ((*it)->condition()) {
buffer.push_back(std::make_shared<A>(**it));
} else {
buffer.push_back(*it);
}
}
as = std::unordered_set<std::shared_ptr<A>>(buffer.begin(),buffer.end());
When you call as.erase(it) the iterator it become invalidated. Inserting into an unordered associative containers invalidates all iterators. Thus, the insertion needs to be separated from the iterator. Avoiding the insertions is also necessary to avoid processing the newly inserted objects:
std::vector<std::shared_ptr<A>> replaced;
for (auto it = as.begin(); it != as.end(); ) {
if ((*it)->condition()) {
replaced.push_back(std::make_shared<A>(**it));
as.erase(it++);
}
else {
++it;
}
}
std::copy(replaced.begin(), replaced.end(), std::inserter(as, as.begin());
I'd put this as a comment on #bitmask's answer. Why not just use the vector for the replaced elements?
std::vector<decltype(as)::value_type> buffer;
buffer.reserve(as.size());
for (auto it = as.begin(); it != as.end(); )
{
if ((*it)->condition())
{
buffer.push_back(*it);
it = as.erase(it);
}
else
{
++it;
}
}
as.insert(buffer.begin(),buffer.end());
And, if *it is already a shared_ptr<A>, I fail to see a reason to make_shared() again. Just assign and let the copy constructor/assignment operators work their magic.
In your case you can just swap in my opinion:
for(auto iter = as.begin(); iter != as.end(); ++iter)
{
if(/*Check deletion condition here*/)
{
auto newItem = std::make_shared<A>(/*...*/);
swap(*iter, newItem);
}
}
I had trouble searching for potential duplicates because I'm not sure what the correct terminology is.
If I have many vectors which are already created, how can I loop through them? To make things simple, suppose I have three vectors of strings named "vec_one", "vec_two", "vec_three".
I want to do something like:
for i in ("vec_one", "vec_two", "vec_three") {
for (vector<string>::const_iterator iter = i.begin(); iter != i.end(); ++iter) {
//do something with the elements ***and I need to access "i"***, that is, the vector name.
}
}
This would be the same as writing three different for loops, but would be more readable and in fact I have more than three in my non-simple application.
Note that because I need to access the vector name (see the comment), I can't just merge them all together and then run one loop.
You can do it with an array:
const vector<string>* varr[] = { &vec_one, &vec_two, &vec_three, &etc };
for (auto vec = begin(varr); vec < end(varr); ++vec)
for (vector<string>::const_iterator iter = begin(**vec); iter != end(**vec); ++iter)
//do something with the elements
You could put the the vectors in a vector<std::pair<std::string, std::vector<...>*>:
std::vector<std::pair<std::string, std::vector<std::string>*> > vectors;
vectors.emplace_back(std::string("vec_one"), &vec_one); //or push_back(std::make_pair(...)) in C++03
vectors.emplace_back(std::string("vec_two"), &vec_two);
vectors.emplace_back(std::string("vec_three"), &vec_three);
for(auto iter = vectors.begin(); iter != vectors.end(); ++iter)//used c++11 auto here for brevity, but that isn't necessary if C++11 is not availible
for(auto vecIter = iter->second->begin(); vecIter != iter->second->end(); ++vecIter)
//get name with iter->first, body here
That way you can get the name easily from the outer iterator.
If you use C++11 you can use std::array instead:
std::array<std::pair<std::string, std::vector<std::string>*>, 3> vectors =
{
std::make_pair(std::string("vec_one"), &vec_one),
std::make_pair(std::string("vec_two"), &vec_two),
std::make_pair(std::string("vec_three"), &vec_three)
};
In C++03 you could use buildin arrays instead, but unless the extra overhead for the vector is a problem for you (unlikely) I don't see a compelling reason to do so. boost::array is also a noteworthy alternative if you can't use C++11
If you do need the absolute optimal performance it might be worthwile to directly use const char* instead of std::string for the names.
Probably the easiest way would be to have your vectors in an array (or a vector-of-vectors if there is a variable number of them).
I guess you'd also want an array of "vector names" to satisfy your second condition.
I am looping through a vector with a loop such as for(int i = 0; i < vec.size(); i++). Within this loop, I check a condition on the element at that vector index, and if a certain condition is true, I want to delete that element.
How do I delete a vector element while looping over it without crashing?
The idiomatic way to remove all elements from an STL container which satisfy a given predicate is to use the remove-erase idiom. The idea is to move the predicate (that's the function which yields true or false for some element) into a given function, say pred and then:
static bool pred( const std::string &s ) {
// ...
}
std::vector<std::string> v;
v.erase( std::remove_if( v.begin(), v.end(), pred ), v.end() );
If you insist on using indices, you should not increment the index for every element, but only for those which didn't get removed:
std::vector<std::string>::size_type i = 0;
while ( i < v.size() ) {
if ( shouldBeRemoved( v[i] ) ) {
v.erase( v.begin() + i );
} else {
++i;
}
}
However, this is not only more code and less idiomatic (read: C++ programmers actually have to look at the code whereas the 'erase & remove' idiom immediately gives some idea what's going on), but also much less efficient because vectors store their elements in one contiguous block of memory, so erasing on positions other than the vector end also moves all the elements after the segment erased to their new positions.
If you cannot use remove/erase (e.g. because you don't want to use lambdas or write a predicate), use the standard idiom for sequence container element removal:
for (auto it = v.cbegin(); it != v.cend() /* not hoisted */; /* no increment */)
{
if (delete_condition)
{
it = v.erase(it);
}
else
{
++it;
}
}
If possible, though, prefer remove/erase:
#include <algorithm>
v.erase(std::remove_if(v.begin(), v.end(),
[](T const & x) -> bool { /* decide */ }),
v.end());
Use the Erase-Remove Idiom, using remove_if with a predicate to specify your condition.
if(vector_name.empty() == false) {
for(int i = vector_name.size() - 1; i >= 0; i--)
{
if(condition)
vector_name.erase(vector_name.at(i));
}
}
This works for me. And Don't need to think about indexes have already erased.
Iterate over the vector backwards. That way, you don't nuke the ability to get to the elements you haven't visited yet.
I realize you are asking specifically about removing from vector, but just wanted to point out that it is costly to remove items from a std::vector since all items after the removed item must be copied to new location. If you are going to remove items from the container you should use a std::list. The std::list::erase(item) method even returns the iterator pointing to the value after the one just erased, so it's easy to use in a for or while loop. Nice thing too with std::list is that iterators pointing to non-erased items remain valid throughout list existence. See for instance the docs at cplusplus.com.
That said, if you have no choice, a trick that can work is simply to create a new empty vector and add items to it from the first vector, then use std::swap(oldVec, newVec), which is very efficient (no copy, just changes internal pointers).