Is it possible to compare two iterators? A comparision using std::min
void change ( typename TList <Item *>::Type ::iterator it_begin, typename TList <Item*>::Type ::iterator it_end )
{
....
this->items.resize ( index );
std::sort ( it_begin, std::min (it_end, it_begin += index - 1); //Compare two iterators, exception
....
}
throws the following exception:
Assertion failed: Vector iterators incompatible...
Is there any other way of the comparision?
Yes. But I doubt if you can do that with std::min.
You can use std::distance function to calculate the distance between two iterators. And then you can use the distance to determine which iterator is the smaller one. Once you know the smaller iterator, you can pass that to std::sort function.
Here is small illustration how to calculate distance:
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> v(100); //vector of size 100
std::cout <<(std::distance(v.begin(), v.begin() + 10))<< std::endl;
std::cout <<(std::distance(v.begin() +25, v.begin() +10))<< std::endl;
}
Output:
10
-15
Hope that gives you enough idea how to proceed to do what you want to.
In the book C++ Primer 5th Ed. on p.111 section 3.4.2 Iterator Arithmetic says,
we can use == and != to compare to valid iterators into any of the library containers.
The section also tells us that iterators for string and vector support relational operators (aka iterator arithmetic) which include >, >=, <, <=.
To answer the question, std::distance() can be used to measure the distance to the begin() iterator, and these distances can then be compared. However, as pointed out by Ben, there are other problems with your code. See http://www.cplusplus.com/reference/std/iterator/distance/
After calling resize, all your existing iterators are invalid.
Furthermore, that line invokes undefined behavior, since you're both changing it_begin and reading from it, in an undetermined order.
Related
In other words, what I mean to say is : Is itr+=2 a valid argument in c++ ?, where (itr is an iterator to first element of the set). If so, then the following piece of code should work:
In this piece if code, the code written in /comment section/ functions well, while the code not in comment section do not. Help me out to iterate alternate elements.
#include <bits/stdc++.h>
using namespace std;
int main()
{
set<int> s;
s.insert(5);
s.insert(7);
s.insert(8);
auto it=s.begin();
cout<<*it<<'\n';
it+=2;
cout<<*it<<'\n';
/*for(auto it=s.begin();it!=s.end();it++)
cout<<*it<<" ";*/
return 0;
}
Is itr+=2 a valid argument in c++?
It depends on the container type. For example, it would be perfectly valid for std::vector or std::array, but not for std::set. Each container, due to its nature, provides different types of iterators. std::set only provides BidirectionalIterator, which do not support jumping over arbitrary number of elements, only incrementation and decrementation.
However, you can use std::advance() from <iterator> library (or just increment the iterator twice). Beware that you must never increment end() iterator, so you need to take it into account in loop condition.
for(auto it=s.begin(); it != s.end() && it != std::prev(s.end()); std::advance(it, 2))
Can I do normal computations with iterators, i.e. just increment it by adding a number?
As an example, if I want to remove the element vec[3], can I just do this:
std::vector<int> vec;
for(int i = 0; i < 5; ++i){
vec.push_back(i);
}
vec.erase(vec.begin() + 3); // removes vec[3] element
It works for me (g++), but I'm not sure if it is guaranteed to work.
It works if the iterator is a random access iterator, which vector's iterators are (see reference). The STL function std::advance can be used to advance a generic iterator, but since it doesn't return the iterator, I tend use + if available because it looks cleaner.
C++11 note
Now there is std::next and std::prev, which do return the iterator, so if you are working in template land you can use them to advance a generic iterator and still have clean code.
A subtle point is that the operator+ takes a Distance; i.e., a signed integer. If you increment the iterator by an unsigned, you may lose precision and run into a surprise. For example on a 64 bit system,
std::size_t n = (1 << 64) - 2;
std::vector<double> vec(1 << 64);
std::vector<double> slice(vec.begin() + n, vec.end());
leads to implementation-defined behavior. With g++ or clang, you can ask the compiler to warn you about such undesired conversions with the warning flag -Wsign-conversion that is not part of the canonical -Wall or -Wextra.
A work-around is to work on the pointer directly
std::vector<double> slice(vec.data() + n, vec.data() + vec.size());
It's not pretty but correct. In some occasions, you need to construct the iterator manually, for example
std::vector<double>::iterator fromHere{vec.data() + n};
vec.erase(fromHere, vec.end());
It works with random access iterators. In general you may want to look at std::advance which is more generic. Just be sure to understand performance implications of using this function template.
Number arithmetic is possible only with random access iterators such as those in std::vector and std::deque.
std::vector<int>list={1,2,3,4,5,6,7,8};
auto last_v=*(list.end()-1);
auto third_last_v=*(list.end()-3);
std::cout<<"Last & 3rd last entry for vector:"<<last_v<<","<<third_last_v<<std::endl;
will output 8 and 6, however for std::map, std::multimap, std::set, std::multiset having bidirectional iterator
std::map<int,std::string> map_={{1,"one"},{2,"two"},{3,"three"}};
auto last_mp=*(map_.end()-1);
auto third_last_mp=*(map_.end()-3);
std::cout<<"Last & 3rd last entry for map:("<<last_mp.first<<","<<last_mp.second<<") and ("<<third_last_mp.first<<","<<third_last_mp.second<<")"<<std::endl;
will result in
error: no match for ‘operator-’ (operand types are ‘std::map, int>::iterator {aka std::_Rb_tree_iterator, int> >}’ and ‘int’)
For bidirectional iterator std::next(),std::prev or std::advance() works
std::map<int,std::string> map_={{1,"one"},{2,"two"},{3,"three"}};
auto last_mp=*std::prev(map_.end(),1);
auto third_last_mp=*std::prev(map_.end(),3);
std::cout<<"Last & 3rd last entry for map:("<<last_mp.first<<","<<last_mp.second<<") and ("<<third_last_mp.first<<","<<third_last_mp.second<<")"<<std::endl;
will output (3,three) and (1,one). On a similar note std::unordered_map has a forward iterator, so here std::next() makes sense to use.
Could this be the worst named function in the STL? (rhetorical question)
std::remove_copy_if() doesn't actually appear to do any removing. As best I can tell, it behaves more like copy_if_not.
The negation is a bit confusing, but can be worked around with std::not1(), however I might be misunderstanding something as I cannot fathom what this function has to do with removing - am I missing something?
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
Editing to add an example so readers are less confused.
The following program appears to leave the input range (V1) untouched:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using std::cout;
using std::endl;
int main (void)
{
std::vector<int> V1, V2;
V1.push_back(-2);
V1.push_back(0);
V1.push_back(-1);
V1.push_back(0);
V1.push_back(1);
V1.push_back(2);
std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
std::remove_copy_if(
V1.begin(),
V1.end(),
std::back_inserter(V2),
std::bind2nd(std::less<int>(), 0));
std::copy(V2.begin(), V2.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
}
It outputs:
-2 0 -1 0 1 2
0 0 1 2
-2 0 -1 0 1 2
I was expecting so see something like:
-2 0 -1 0 1 2
0 0 1 2
0 0 1 2 ? ? ?
Where ? could be any value. But I was surprised to see that the input range was untouched, & that the return value is not able to be used with (in this case) std::vector::erase(). (The return value is an output iterator.)
Could this be the worst named function in the STL?
A bit of background information: in the standard library (or the original STL), there are three concepts, the containers, the iterators into those containers and algorithms that are applied to the iterators. Iterators serve as a cursor and accessor into the elements of a range but do not have a reference to the container (as mentioned before, there might not even be an underlying container).
This separation has the nice feature that you can apply algorithms to ranges of elements that do not belong to a container (consider iterator adaptors like std::istream_iterator or std::ostream_iterator) or that, belonging to a container do not consider all elements (std::sort( v.begin(), v.begin()+v.size()/2 ) to short the first half of the container).
The negative side is that, because the algorithm (and the iterator) don't really know of the container, they cannot really modify it, they can only modify the stored elements (which is what they can access). Mutating algorithms, like std::remove or std::remove_if work on this premise: they overwrite elements that don't match the condition effectively removing them from the container, but they do not modify the container, only the contained values, that is up to the caller in a second step of the erase-remove idiom:
v.erase( std::remove_if( v.begin(), v.end(), pred ),
v.end() );
Further more, for mutating algorithms (those that perform changes), like std::remove there is a non-mutating version named by adding copy to the name: std::remove_copy_if. None of the XXXcopyYYY algorithms are considered to change the input sequence (although they can if you use aliasing iterators).
While this is really no excuse for the naming of std::remove_copy_if, I hope that it helps understanding what an algorithm does given its name: remove_if will modify contents of the range and yield a range for which all elements that match the predicate have been removed (the returned range is that formed by the first argument to the algorithm to the returned iterator). std::remove_copy_if does the same, but rather than modifying the underlying sequence, it creates a copy of the sequence in which those elements matching the predicate have been removed. That is, all *copy* algorithms are equivalent to copy and then apply the original algorithm (note that the equivalence is logical, std::remove_copy_if only requires an OutputIterator, which means that it could not possibly copy and then walk the copied range applying std::remove_if.
The same line of reasoning can be applied to other mutating algorithms: reverse reverses the values (remember, iterators don't access the container) in the range, reverse_copy copies the elements in the range to separate range in the reverse order.
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
There is no such algorithm in the STL, but it could be easily implementable:
template <typename FIterator, typename OIterator, typename Pred>
FIterator splice_if( FIterator first, FIterator last, OIterator out, Pred p )
{
FIterator result = first;
for ( ; first != last; ++first ) {
if ( p( *first ) ) {
*result++ = *first;
} else {
*out++ = *first;
}
}
return result;
}
is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
The closest thing I can think of is std::stable_partition:
std::vector<int> v;
// ...
auto it = std::stable_partition(v.begin(), v.end(), pick_the_good_elements);
std::vector<int> w(std::make_move_iter(it), std::make_move_iter(v.end()));
v.erase(it, v.end());
Now v will contain the "good" elements, and w will contain the "bad" elements.
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
Not really. The idea is that the modifying algorithms are allowed to "move" (not in the C++ sense of the word) elements in a container around but cannot change the length of the container. So the remove algorithms could be called prepare_for_removal.
By the way, C++11 provides std::copy_if, which allows you to copy selected elements from one container to another without playing funny logic games with remove_copy_if.
You are right, that is what it does... std::remove_copy_if copies the vector, removing anything that matches the pred.
std::remove_if ... removes on condition (or rather, shuffles things around).
I agree that remove is not the best name for this family of functions.
But as Luc said, there's a reason for it working the way it does, and the GoTW item that he mentions explains how it works. remove_if works exactly the same way as remove - which is what you would expect.
You might also want to read this Wikibooks article.
s1 and s2 are sets (Python set or C++ std::set)
To add the elements of s2 to s1 (set union), you can do
Python: s1.update(s2)
C++: s1.insert(s2.begin(), s2.end());
To remove the elements of s2 from s1 (set difference), you can do
Python: s1.difference_update(s2)
What is the C++ equivalent of this? The code
s1.erase(s2.begin(), s2.end());
does not work, for s1.erase() requires iterators from s1.The code
std::set<T> s3;
std::set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(s3, s3.end());
s1.swap(s3);
works, but seems overly complex, at least compared with Python.
Is there a simpler way?
Using std::set_difference is the idiomatic way to do this in C++. You have stumbled across one of the primary differences (pun intended) between C++/STL and many other languages. STL does not bundle operations directly with the data structures. This is why std::set does not implement a difference routine.
Basically, algorithms such as std::set_difference write the result of the operation to another object. It is interesting to note that the algorithm does not require that either or both of the operands are actually std::set. The definition of the algorithm is:
Effects: Copies the elements of the range [first1, last1) which are not present in the range [first2, last2) to the range beginning at result. The elements in the constructed range are sorted.
Requires: The resulting range shall not overlap with either of the original ranges. Input ranges are required to be order by the same operator<.
Returns: The end of the constructed range.
Complexity: At most 2 * ((last1 - first1) + (last2 - first2)) - 1 comparisons
The interesting difference is that the C++ version is applicable to any two sorted ranges. In most languages, you are forced to coerce or translate the calling object (left-hand operand) into a set before you have access to the set difference algorithm.
This is not really pertinent to your question, but this is the reason that the various set algorithms are modeled as free-standing algorithms instead of member methods.
You should iterate through the second set:
for( set< T >::iterator iter = s2.begin(); iter != s2.end(); ++iter )
{
s1.erase( *iter );
}
This will could be cheaper than using std::set_difference - set_difference copies the unique objects into a new container, but it takes linear time, while .erase will not copy anything, but is O(n * log( n ) ).
In other words, depends on the container, you could choose the way, that will be faster for your case.
Thanks David Rodríguez - dribeas for the remark! (:
EDIT: Doh! I thought about BOOST_FOREACH at the very beginning, but I was wrong that it could not be used.. - you don't need the iterator, but just the value.. As user763305 said by himself/herself.
In c++ there is no difference method in the set. The set_difference looks much more awkward as it is more generic than applying a difference on two sets. Of course you can implement your own version of in place difference on sets:
template <typename T, typename Compare, typename Allocator>
void my_set_difference( std::set<T,Compare,Allocator>& lhs, std::set<T,Compare,Allocator> const & rhs )
{
typedef std::set<T,Comapre,Allocator> set_t;
typedef typename set_t::iterator iterator;
typedef typename set_t::const_iterator const_iterator;
const_iterator rit = rhs.begin(), rend = rhs.end();
iterator it = lhs.begin(), end = lhs.end();
while ( it != end && rit != rend )
{
if ( lhs.key_comp( *it, *rit ) ) {
++it;
} else if ( lhs.key_comp( *rit, *it ) ) {
++rit;
} else {
++rit;
lhs.erase( it++ );
}
}
}
The performance of this algorithm will be linear in the size of the arguments, and require no extra copies as it modifies the first argument in place.
You can also do it with remove_if writing your own functor for testing existence in a set, e.g.
std::remove_if(s1.begin(), s1.end(), ExistIn(s2));
I suppose that set_difference is more efficient though as it probably scans both sets only once
Python set is unordered, and is more of an equivalent of C++ std::unordered_set than std::set, which is ordered.
David Rodríguez's algorithm relies on the fact that std::set is ordered, so the lhs and rhs sets can be traversed in the way as exhibit in the algorithm.
For a more general solution that works for both ordered and unordered sets, Kiril Kirov's algorithm should be the safe one to adopt if you are enforcing/preserving the "unorderedness" nature of Python set.
I am trying to understand STL algorithms.
Copy is defined as :
template<class InputIterator, class OutputIterator>
OutputIterator copy ( InputIterator first, InputIterator last, OutputIterator result )
Can some one please explain why does the following works when vectors & deques are mixed but fails when vectors and sets are mixed.
#include <iostream>
#include <algorithm>
#include <vector>
#include <deque>
#include <deque>
#include <set>
using namespace std;
int main () {
int myints[]={10,20,30,40,50,60,70};
vector<int> myvector;
vector<int>::iterator it;
set<int> mset(myints,myints+8);
set<int>::iterator setItr = mset.begin();
deque<int> deq;
deq.resize(10);
deque<int>::iterator deqItr = deq.begin();
myvector.resize(7); // allocate space for 7 elements
copy ( myints, myints+7, myvector.begin() );
copy ( myvector.begin(), myvector.end(), deqItr );
cout << "deque contains:";
for (deque<int>::iterator dit=deq.begin(); dit!=deq.end(); ++dit)
cout << " " << *dit;
cout << endl;
//copy ( myvector.begin(), myvector.end(), setItr );
return 0;
}
I understand vectors/deque have random access iterators, where as set's have bidirectional iterators. I fail to understand why compilation fails when only a input/output iterators are required.
PS : This is just an experiment to increase my understanding :)
Associative containers (in plain C++03) are special containers that keep their elements sorted at all times, commonly implemented as a Red Black Tree. To maintain the order invariant, the set and map iterators provide constant references into the key object, and as such you cannot modify it.
In particular for std::set<T>, the iterator will usually be such that std::iterator_traits< std::set<T>::iterator >::reference is const T&, and as such the assignment implicit in the std::copy operation will fail.
If what you want to do is insert the elements into a set, you can use iterators from the <iterator> header that will perform insert operations in the set:
std::copy( v.begin(), v.end(), std::inserter( s, s.end() ) ); // s is the set
std::vector and std::deque have a way to preallocate space. std::set doesn't. Without preallocating the space, attempting to dereference the iterator you pass to copy produces undefined behavior.
The obvious alternative is to use insert iterators instead -- though, unfortunately, you still neednearly always use different code for a set than a deque or vector:
std::copy(myvector.begin(), myvector.end(), std::back_inserter(mydeque));
std::copy(myvector.begin(), myvector.end(), std::inserter(mySet, mySet.end());
It works for vector and deque because you can allocate space beforehand. With other containers, like map, you need an iterator adapter to do that for you. Look at insert_iterator, for example.