Is it possible to access the std::for_each iterator, so I can erase the current element from an std::list using a lambda (as below)
typedef std::shared_ptr<IEvent> EventPtr;
std::list<EventPtr> EventQueue;
EventType evt;
...
std::for_each(
EventQueue.begin(), EventQueue.end(),
[&]( EventPtr pEvent )
{
if( pEvent->EventType() == evt.EventType() )
EventQueue.erase( ???Iterator??? );
}
);
I've read about using [](typename T::value_type x){ delete x; } here on SO, but VS2010 doesn't seem to like this statement (underlines T as error source).
You are using the wrong algorithm. Use remove_if:
EventQueue.remove_if([&](EventPtr const& pEvent)
{
return pEvent->EventType() == evt.EventType();
});
The STL algorithms do not give you access to the iterator being used for iteration. This is in most cases a good thing.
(In addition, consider whether you really want to use std::list; it's unlikely that it is the right container for your use case. Consider std::vector, with which you would use the erase/remove idiom to remove elements that satisfy a particular predicate.)
no, use a regular for instead.
for( auto it = EventQueue.begin(); it != EventQueue.end(); ++it )
{
auto pEvent = *it;
if( pEvent->EventType() == evt.EventType() )
it = EventQueue.erase( it );
);
Erase is not the only time you may need to know iterator from lambda.
To do this in a more general way, I am using & operator (implicit conversion to iterator) like this :
int main (int argc, char* argv []) {
size_t tmp [6] = {0, 1, 2, 3, 4, 5};
std::list<size_t> ls ((size_t*)tmp, (size_t*) &tmp [6]);
//printing next element
std::for_each ((const size_t*)tmp, (const size_t*) &tmp [5], [] (const size_t& s) {
std::cout << s << "->";
std::cout << *(&s +1) << " ";
});
std::cout << std::endl;
}
Related
Is there any way to write these two class methods, without using loops, lambda functions, and other additional functions? I only want to use the functions and functors from libraries algorithm and functional. I have tried to use while loop and recursion to fugure something out, but still couldn't solve this. I didn't want to post the whole code since it is too long.
(I don't have to use these libraries for << operator, if there is a way to solve this without them, and min and max are lists)
My main goal is not using loops, lambda functions and any additional functions outside the two libraries. EraseNegativeTemperatures is the method which should only erase the registered pairs of temperatures where both of them are negative (I wrote the method in the part which I didn't post, and that method makes pairs where one temperature is from min and the other one from max)
Operator << outputs all the registered temperatures, the min ones in one row and the max ones in the second row; the temperatures in one row are separates by space.
void Temperatures::EraseNegativeTemperatures() {
for (auto it = max.begin(); it != max.end(); it++) {
if (*it < 0) {
auto it1 = it;
auto it2 = min.begin();
while (it1 != max.begin()) {
it2++;
it1--;
}
min.erase(it2);
it = max.erase(it);
}
}
// std::remove_if(min.begin(), min.end(), std::bind(std::less<int>(),
max.begin() + std::placeholders::_1 - min.begin(), 0));
}
// second method
std::ostream &operator<<(std::ostream &flow, const Temperatures &t) {
std::for_each(t.min.begin(), t.min.end(),
[&flow](int x) { flow << x << " "; });
flow << std::endl;
std::for_each(t.max.begin(), t.max.end(),
[&flow](int x) { flow << x << " "; });
flow << std::endl;
return flow;
}
As far as I can see you erase a temperature from each of min and max vector which are reverse of each other.
Added a test if the min temp is also negative.
Totally untested code
void Temperatures::EraseNegativeTemperatures() {
for (auto it = max.begin(); it != max.end(); it++) {
if (*it < 0) {
auto diff = std::distance(max.begin(), it);
if (*(min.rend()+diff) < 0) {
min.erase(min.rend()+diff); // reverse of max
it = max.erase(it);
}
}
}
At first it might be simpler to erase from both lists separately; the following (disallowed) lambda solution will be the starting point:
auto current = max.begin();
min.erase(
remove_if(
min.begin(), min.end(),
[¤t] (int /* ignored! */) { return *current++ < 0; }
),
min.end()
);
This will remove all those elements from the min list that have a corresponding negative value in the max list. Afterwards you can remove the negative values from the max list with an expression you have already found:
max.erase(
remove_if(
max.begin(), max.end(),
std::bind(std::less<int>(), std::placeholders::_1, 0)
),
max.end()
);
The tricky part is now to re-build the lambda with standard library means only.
So we will need the operators above available as ordinary functions so that we can bind to them:
auto dereference = &std::list<int>::iterator::operator*;
auto postIncrement = static_cast<
std::list<int>::iterator (std::list<int>::iterator::*)(int)
>(
&std::list<int>::iterator::operator++
);
The static_cast for getting the second operator is necessary to distinguish the post-increment operator from the pre-increment operator.
Now we need to bind everything to the less-than operator:
auto lt0 = std::bind(
std::less<int>(),
std::bind(dereference, std::bind(postIncrement, std::ref(current), 0)),
0
);
Note the creation of a reference to the iterator! The resulting functor we now can use to erase from min list:
min.erase(remove_if(min.begin(), min.end(), lt0), min.end());
Pretty similarly we can create the functor for outputting the arrays; at first we need the operators available; note that one of is a member function, the other one not:
auto outInt = static_cast<std::ostream& (std::ostream::*)(int)>(
&std::ostream::operator<<
);
auto outChar = static_cast<std::ostream& (*)(std::ostream&, char)>(
&std::operator<<
);
Now we can again bind everything together:
auto out = std::bind(
outChar,
std::bind(outInt, std::ref(flow), std::placeholders::_1),
' '
);
std::for_each(t.min.begin(), t.min.end(), out);
flow << std::endl;
std::for_each(t.max.begin(), t.max.end(), out);
flow << std::endl;
I want to insert new (unique) element into known place (generally somewhere in the middle) of an ordered associative container std::set/std::multiset/std::map/std::multimap using insert (w/ hint) or emplace_hint.
During insertion operation I absolutely sure, that the place to insert is right before the "hint" iterator. Generally I can compare any two non-neighbouring elements in the container, but this operation is strongly heavyweight. To avoid overhead imposed, I provide custom comparator for the container, which contains a references to pointers to both neigbouring elements (they always became known right before the insertion/emplacement operation).
#include <map>
#include <set>
static std::size_t counter = 0;
template< typename T >
struct less
{
T const * const & pl;
T const * const & pr;
bool operator () (T const & l, T const & r) const
{
if (&l == &r) {
return false;
}
if (pl) {
if (&l == pl) {
return true;
}
if (&r == pl) {
return false;
}
}
if (pr) {
if (&r == pr) {
return true;
}
if (&l == pr) {
return false;
}
}
++counter;
return l < r; // very expensive, it is desirable this line to be unrecheable
}
};
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cassert>
int main()
{
using T = int;
T const * pl = nullptr;
T const * pr = nullptr;
less< T > less_{pl, pr};
std::set< T, less< T > > s{less_};
s.insert({1, 2,/* 3, */4, 5});
std::copy(std::cbegin(s), std::cend(s), std::ostream_iterator< T >(std::cout, " "));
std::cout << '\n';
auto const hint = s.find(4);
// now I want to insert 3 right before 4 (and, of course, after 2)
pl = &*std::prev(hint); // prepare comparator to make a cheap insertion
pr = &*hint;
// if hint == std::end(s), then pr = nullptr
// else if hint == std::begin(s), then pl = nullptr
// if I tried to insert w/o hint, then pl = pr = nullptr;
{
std::size_t const c = counter;
s.insert(hint, 3);
assert(counter == c);
}
std::copy(std::cbegin(s), std::cend(s), std::ostream_iterator< T >(std::cout, " "));
std::cout << '\n';
}
Current libc++/libstdc++ implementations allows me to use described comparator, but is there undefined behaviour if I rely on their current behaviour? Can I rely, that insert (w/ hint parameter) or emplace_hint (and modern insert_or_assign/try_emplace w/ hint parameter for map/multimap) don't touch any other elements other then pointed by pl and pr? Is it implementation-defined thing?
Why I want this strange thing? IRL I tried to implement Fortune's algorithm to find Voronoi diagram on the plane using native STL's self-balanced binary search tries. std::set is used to store current state of a part of a so-called beach line: a chain of sorted endpoints. When I add a new endpoint I always know the place where to insert it right before the insertion. It would be best if I can add assert(false); before or throw std::logic_error{};/__builtin_unreachable(); instead of last return in comparator functor. I only can do it if there is corresponding logical guarantee. Can I do this?
In the C++ Standard Map Library, a call to the iteration functions returns an iterator pointer,
std::map<int, int> map;
std::map<int, int>::iterator ite = map.find(1);
But, when the iterator is used, it must be accessed as a pointer variable,
int first = ite->first;
int second = ite->second;
Why is this the case when we are putting the obtained value from the find function into a non-pointer. Shouldn't the correct syntax be:
std::map<int, int>::iterator *pIte = map.find(1)
or if using the original syntax,
int first = ite.first;
int second = ite.second;
since we are obtaining a value, and not a pointer from the function's return value? It is also not clarified in the documentation. Why is this the case?
As #jaggedSpire suggested, iterators are supposed to act like ptrs, having defined the operators *, ->, etc. But the thing is, an iterator isn't an explicit pointer. The syntax you suggested:
std::map<int, int>::iterator *pIte = map.find(1);
Is a pointer to an iterator, not just an iterator. The reason when you wrote:
std::map<int, int>::iterator pIte = map.find(1);
you have to write: ite->first is because operator-> is defined for iterators. This means that iterators are supposed to act like pointers.
The call of the function
std::map<int, int>::iterator ite = map.find(1);
returns iterator that behaves like pointers.
So you need to use the syntax of accessing objects using pointers
int first = ite->first;
int second = ite->second;
Or you could write instead
int first = ( *ite ).first;
int second = ( *ite ).second;
Compare for example
#include <iostream>
#include <iterator>
#include <algorithm>
#include <utility>
int main()
{
const size_t N = 5;
std::pair<int, int> a[N] = { { 2, 2 }, { 4, 4 }, { 1, 1 }, { 3, 3 }, { 5, 5 } };
std::pair<int, int> *it = std::find( std::begin( a ), std::end( a ), std::make_pair( 1, 1 ) );
if ( it != std::end( a ) )
{
std::cout << it - a << ": "
<< "{ " << it->first << ", " << it->second << " }" << std::endl;
}
return 0;
}
The program output is
2: { 1, 1 }
Here it is explicitly declared like a pointer.
A number of posts I've read lately claim for(const auto &it : vec) is the same as using the longer iterator syntax for(std::vector<Type*>::const_iterator it = vec.begin(); it != vec.end(); it++). But, I came upon this post that says they're not the same.
Currently, I'm trying to erase an element in a for loop, after it is used, and wondering if there is any way to convert const auto &it : nodes to std::vector<txml::XMLElement*>::iterator?
Code in question:
std::vector<txml2::XMLElement *> nodes;
//...
for (const auto &it : nodes)
{
//...
nodes.erase(it);
}
I pretty sure I could just rewrite std::vector<txml2::XMLElement*> as a const pointer, but would prefer not to since this code is just for debugging in the moment.
You should not be attempting to convert the range declaration in your range based for loop to an iterator and then deleting it whilst iterating. Even adjusting iterators while iterating is dangerous, and you should instead rely on algorithms.
You should use the Erase-remove idom.
You can use it with remove_if.
It would look something like:
nodes.erase( std::remove_if(nodes.begin(), nodes.end(), [](auto it){
//decide if the element should be deleted
return true || false;
}), nodes.end() );
Currently in the technical specifications, is erase_if.
This is a cleaner version of the same behaviour shown above:
std::erase_if(nodes,[](auto it){
//decide if the element should be deleted
return true || false;
});
You don't get an iterator but a reference to the element. Unless you want to do a std::find with it, it's pretty hard to get an iterator out of it.
Vectors are nice, so you could increase a counter per element and do nodes.begin() + counter to get the iterator, but it'd sort of defeat the point.
Also erasing the iterator in the for loop will result in you iterating after the end of the vector, you can test this code:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {0,1,2,3,4,5,6};
for (int x : v) {
cout << x << endl;
if (x == 2) {
v.erase(v.begin() + 2);
}
}
return 0;
}
If you want to use iterators, just do a loop with them, if in addition you want to erase one mid-loop you have to follow this answer:
for (auto it = res.begin() ; it != res.end(); ) {
const auto &value = *it;
if (condition) {
it = res.erase(it);
} else {
++it;
}
}
Note that you don't need to specify the whole type of the iterator, auto works just as well.
I want to remove some elements from a vector and am using remove_if algorithm to do this. But I want to keep track of the removed elements so that I can perform some operation on them later. I tried this with the following code:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
struct IsEven
{
bool operator()(int n)
{
if(n % 2 == 0)
{
evens.push_back(n);
return true;
}
return false;
}
vector<int> evens;
};
int main(int argc, char **argv)
{
vector<int> v;
for(int i = 0; i < 10; ++i)
{
v.push_back(i);
}
IsEven f;
vector<int>::iterator newEnd = remove_if(v.begin(), v.end(), f);
for(vector<int>::iterator it = f.evens.begin(); it != f.evens.end(); ++it)
{
cout<<*it<<"\n";
}
v.erase(newEnd, v.end());
return 0;
}
But this doesn't work as remove_if accepts the copy of my functor object, so the the stored evens vector is not accessible. What is the correct way of achieving this?
P.S. : The example, with even and odds is just for example sake, my real code is somethinf different. So don't suggest a way to identify even or odds differently.
The solution is not remove_if, but it's cousin partial_sort partition. The difference is that remove_if only guarantees that [begin, middle) contains the matching elements, but partition also guarantees that [middle, end) contains the elements which didn't match the predicate.
So, your example becomes just (note that evens is no longer needed):
vector<int>::iterator newEnd = partition(v.begin(), v.end(), f);
for(vector<int>::iterator it = newEnd; it != v.end(); ++it)
{
cout<<*it<<"\n";
}
v.erase(newEnd, v.end());
Your best bet is std::partition() which will rearrange all elts in the sequence such as all elts for which your predicate return true will precede those for which it returns false.
Exemple:
vector<int>::iterator bound = partition (v.begin(), v.end(), IsEven);
std::cout << "Even numbers:" << std::endl;
for (vector<int>::iterator it = v.begin(); it != bound; ++it)
std::cout << *it << " ";
std::cout << "Odd numbers:" << std::endl;
for (vector<int>::iterator it = bound; it != v.end(); ++it)
std::cout << *it << " ";
You can avoid copying your functor (i.e. pass by value) if you pass ist by reference like this:
vector<int>::iterator newEnd = remove_if(v.begin(), v.end(),
boost::bind<int>(boost::ref(f), _1));
If you can't use boost, the same is possible with std::ref. I tested the code above and it works as expected.
An additional level of indirection. Declare the vector locally, and
have IsEven contain a copy to it. It's also possible for IsEven to
own the vector, provided that it is dynamically allocated and managed by
a shared_ptr. In practice, I've generally found the local variable
plus pointer solution more convenient. Something like:
class IsEven
{
std::vector<int>* myEliminated;
public:
IsEven( std::vector<int>* eliminated = NULL )
: myEliminated( eliminated )
{
}
bool
operator()( int n ) const
{
bool results = n % 2 == 0;
if ( results && myEliminated != NULL ) {
myEliminated->push_back( n );
}
return results;
}
}
Note that this also allows the operator()() function to be const. I
think this is formally required (although I'm not sure).
The problem that I see with the code is that the evens vector that you create inside the struct gets created everytime the remove_if algorithm calls it. So no matter if you pass in a functor to remove_if it will create a new vector each time. So once the last element is removed and when the function call ends and comes out of the function the f.evens will always fetch an empty vector. This could be sorted in two ways,
Replace the struct with a class and declare evens as static (if that is what you wanted)
Or you could make evens global. I wouldn't personally recommend that( it makes the code bad, say no to globals unless you really need them).
Edit:
As suggested by nabulke you could also std::ref something likke this, std::ref(f). This prevents you from making the vector global and avoids for unnecessary statics.
A sample of making it global is as follows,
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
vector<int> evens;
struct IsEven
{
bool operator()(int n)
{
if(n % 2 == 0)
{
evens.push_back(n);
return true;
}
return false;
}
};
int main(int argc, char **argv)
{
vector<int> v;
for(int i = 0; i < 10; ++i)
{
v.push_back(i);
}
IsEven f;
vector<int>::iterator newEnd = remove_if(v.begin(), v.end(), f);
for(vector<int>::iterator it = evens.begin(); it != evens.end(); ++it)
{
cout<<*it<<"\n";
}
v.erase(newEnd, v.end());
return 0;
}
This code seems to work just fine for me. Let me know if this is not what you wanted.
You may have another solution; only if you don't need to remove elts in the same time (do you?). With std::for_each() which returns a copy of your functor. Exemple:
IsEven result = std::for_each(v.begin(), v.end(), IsEven());
// Display the even numbers.
std::copy(result.evens.begin(), result.evens.end(), std::ostream_iterator<int> (cout, "\n"));
Take note that it is always better to create unnamed variables in c++ when possible. Here that solution does not exactly answer your primary issue (removing elts from the source container), but it reminds everyone that std::for_each() returns a copy of your functor. :-)