Based on the implementation of Iter, I have difficulties to understand operator!= and don't understand why it doesn't check _p_vec?
This is the suggested implementation of operator!= that ONLY compares the _pos.
class Iter
{
public:
Iter (const IntVector* p_vec, int pos)
: _pos( pos )
, _p_vec( p_vec )
{ }
// these three methods form the basis of an iterator for use with
// a range-based for loop
bool operator!= (const Iter& other) const
{
return _pos != other._pos;
}
...
...
private:
int _pos;
const IntVector *_p_vec;
};
However, I think the correct way to do this as follows. In other words, we have to compare both _pos and _p_vec.
bool Iter::operator!= (const Iter& other) const
{
return _p_vec != other._p_vec || _pos != other._pos;
}
Question> Whose code is correct?
===Update on how std::vector works on comparison of iterator====
std::vector<int> vecOne { 1, 2, 3};
std::vector<int> vecTwo { 4, 5, 6};
auto iterOne = vecOne.begin();
std::advance(iterOne, 1);
auto iterTwo = vecTwo.begin();
std::advance(iterTwo, 1);
if ( iterOne == iterTwo)
std::cout << "iterOne == iterTwo" << std::endl;
else
std::cout << "iterOne != iterTwo" << std::endl;
Output is : iterOne != iterTwo
However,
std::vector<int> foo;
std::vector<int> bar;
if ( foo.begin() == bar.begin() )
std::cout << "foo.begin() == bar.begin()" << std::endl;
else
std::cout << "foo.begin() != bar.begin()" << std::endl;
Output is : foo.begin() == bar.begin()
GCC (version 4.7.1)
Also comparing the underlying container reference is an improvement to make sure that, for example, the begin() iterators of two different containers compare equal.
However, iterators of different containers are rarely compared (when using STL algorithms, they never will). So this might be considered an optimization. Think of a loop in which you step from begin() to end(), so the only iterators you are comparing are the "current" one and end(), which are of the same container.
Comparing iterators of standard containers (vector, etc.) is considered undefined behavior. Indeed, since they never are compared in (good) code (for example the standard algorithms), it doesn't have to define a behavior for such cases.
So the author of this Iter class might also want to come back to this point and say: "Comparing iterators of different vectors is undefined behavior."
This being said, if you want to ensure that you never compare iterators of different containers, leave out this check and maybe assert it for debug builds (but don't check it in release builds).
A good example where you might want to compare iterators of different containers is for linked lists, where you define the end of the list being a null pointer (or a pointer to a static null item instance). Consider the iterator being a pointer to a linked list item; in this case, the end() iterator is just a null pointer (or points to this null item). It is the same one for all containers, so you can't implement the check in your comparison method in such cases. Maybe this is one of the reasons why such a comparison isn't defined -- it should return "unequal" when comparing end iterators of different lists, but it can't.
As a general rule, users of iterators are not supposed to compare iterators from different containers. In the standard library, doing so is undefined behavior.
So assuming you are only trying to create iterators that are as robust as standard library ones, comparing the container is not required. However, if you have the pointer to container around, then it would be polite to check that the containers match at least in debug, then assert that you shouldn't be making this comparison.
You are free to check it in release as well, but if your iterator using code is also supposed to work with standard containers, then relying on iterators from different containers comparing not equal is not advised.
See comparing iterators from different containers for someone talking about how it is undefined behavior.
Related
Given the following algorithm:
#include <iostream>
#include <list>
int main ()
{
std::list<int> mylist = {5,10,15,20};
std::cout << "mylist contains:"<<"\n";
//for (auto it = mylist.begin(); it != mylist.end(); ++it)
auto it = mylist.begin();
while ( it != mylist.end())
{
std::cout << *it;
std::cout << " "<< &it<<std::endl;
it++;
}
std::cout << '\n';
return 0;
}
The output of this program is:
mylist contains:
5 0x7dc9445e5b50
10 0x7dc9445e5b50
15 0x7dc9445e5b50
20 0x7dc9445e5b50
Since we are moving our iterator, why the address doesn't change?
I was excepting a 4 bytes offset of the reference.
Try this instead:
std::cout << " "<< &*it<<std::endl;
Read this for a description of legacy bidirectional iterators.
https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator
It's not incredibly obvious from this documentation but for this iterator and for iterators in general throughout STL the operator *() will return either:
T & operator *();
or
const T & operator *() const; // for const iterators (list iterator in this case).
I hope this is a bit more explanatory than my previous rather terse answer.
Your problem is pretty simple: it is a variable. Right now, you're printing out the address of that variable. You assign different values to that variable, but the variable is stored at the same location in memory for the entirety of its existence, so when you print out its address, you see the same value every time.
What you want to do is print out the value stored in that variable--the address of the object to which the iterator refers. In the case of an iterator, it can be somewhat tricky to do that, because an iterator is an abstraction--by design, you don't really know what it contains.
We can, however, take a fairly solid guess about how an iterator for an std::list is probably implemented. In particular, it's probably something like this:
template <class T>
class iterator {
T *data;
public:
T &operator*() { return *data; }
// ... and many more functions we don't care about for now
};
The important point here is that although it may store different data to produce its result, operator* needs to return a reference to the object to which the iterator refers. So, to get the address that's (at least effectively) stored in the iterator, we can use operator* to get a reference to the object, then & to take the address of that object.
The downside: while this tells you the addresses of the objects the iterator refers to at different times, it doesn't necessarily tell you what the iterator itself really contains. As long as the iterator produces the correct results from the specified operations, the iterator is free to produce them in essentially any way it sees fit (but that said, with an iterator for an std::list, yes, it's probably going to use a pointer).
I have a custom vector container that internally stores item a linear array. Last night, I was trying to implement custom iterators for my class to be able to use them with STL algorithms. I have had some success that you can see in here:
Live example with custom iterators
While doing so, I discovered I can merely pass raw pointers to STL algorithm and they just seem to work fine. Here's the example without any iterators:
#include <cstddef>
#include <iostream>
#include <iterator>
#include <algorithm>
template<typename T>
class my_array{
T* data_;
std::size_t size_;
public:
my_array()
: data_(NULL), size_(0)
{}
my_array(std::size_t size)
: data_(new T[size]), size_(size)
{}
my_array(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
}
my_array(const T* first, const T* last){
size_ = last - first;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = first[i];
}
~my_array(){
delete [] data_;
}
const my_array<T>& operator=(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
return other;
}
const T& operator[](std::size_t idx) const {return data_[idx];}
T& operator[](std::size_t& idx) {return data_[idx];}
std::size_t size(){return size_;}
T* begin(){return data_;}
T* end(){return data_+size_;}
};
template<typename T>
void print(T t) {
std::cout << t << std::endl;
}
int main(){
typedef float scalar_t;
scalar_t list [] = {1, 3, 5, 2, 4, 3, 5, 10, 10};
my_array<scalar_t> a(list, list+sizeof(list)/sizeof(scalar_t));
// works!
for (scalar_t* it = a.begin(), *end = a.end();
it != end; ++it)
std::cout << ' ' << *it;
std::cout << std::endl;
// works!
std::for_each(a.begin(), a.end(), print<scalar_t>);
std::cout << std::endl;
// works!
my_array<int> b(a.size());
std::copy(a.begin(), a.end(), b.begin());
// works!
scalar_t* end = std::remove(a.begin(), a.end(), 5);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
std::random_shuffle(a.begin(), end);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
std::cout << "Counts of 3 in array = " << std::count(a.begin(), end, 3) << std::endl << std::endl;
// works!
std::sort(a.begin(), end);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
if (!std::binary_search(a.begin(), a.end(), 5))
std::cout << "Removed!" << std::endl;
return 0;
}
Live example without iterators
My questions here are the following:
Does this always work for containers that have linear storage? I know that this would not work for linked-lists for example.
If they do work in this situation, why should I ever go through the hassle of implementing iterators anyway? I know how iterators generalize my code and whatnot, but if this simple array is all I ever need then I don't see the point.
What are the negative issues of what I'm doing if this approach would always work? For one thing, I can see I'm breaking data encapsulation.
One of the features of iterators being based on operator-overloading, is that pointers are already random-access iterators. This was a big design win in the early days of STL, as it made it easier to use algorithms with existing code (as well as making the interface more familiar to programmers). It's perfectly reasonable to wrap an array, add typedef T* iterator; typedef const T* const_iterator, return &array[0] from your begin() and &array[size] from your end(), and then use your container with any iterator-based algorithm. As you already realise, this will work for any container where elements are contiguous in memory (such as an array).
You might implement 'real' iterators if:
You have a different-shaped container (such as a tree or list);
You want to be able to resize the array without invalidating the iterators;
You want to add debugging checks to your iterator use, for example to check if the iterator is used after being invalidated or after the container has been deleted, or to bounds-check;
You want to introduce type-safety, and make sure people can't accidentally assign an arbitrary T* to a my_array::iterator.
I'd say this last advantage alone is well worth writing a trivial wrapper class for. If you don't take advantage of C++'s type system by making different kinds of thing have different types, you might as well switch to Javascript :-)
Yes. See Effective STL, Item 16, which demonstrates with linear storage containers you can simply take the address of an item and work with that pointer as if it pointed to a simple array.
I think you answered your own question – you probably shouldn't, if you know the simple array is all you'll ever need.
Probably the biggest issue is just that – breaking data encapsulation. Consider whether or not an abstraction such as an explicit iterator type would buy you anything versus the cost.
Does this always work for containers that have linear storage?
Yes, the iterator concepts were designed so that pointers could act as iterators over arrays.
If they do work in this situation, why should I ever go through the hassle of implementing iterators anyway?
There's no good reason to define your own iterator type in this situation, unless you want to do something like bounds-checking which can't be done with a simple pointer.
One slight benefit would be that you could include nested typedefs for the iterator's traits, as some of the standard iterator types do; but using pointers these are available from std::iterator_traits<T*> anyway.
What are the negative issues of what I'm doing if this approach would always work? For one thing, I can see I'm breaking data encapsulation.
To make the interface more consistent with STL-style containers, you should define iterator and const_iterator types (typedef aliases for the pointers), and provide const overloads of begin and end; and perhaps cbegin and cend for C++11 compatiblity.
There are various other requirements that you might want to conform to; see section 23.2 of the C++ standard for the gory details. But in general, it's more important to make iterators conform to their requirements, since STL-style algorithms work with iterators rather than containers, and by using pointers you already conform to those requirements.
It happens that pointers provide the interface required of random access iterators (dereference, increment, addition, difference, etc) and can be treated just like iterators.
It should always work for containers with contiguous storage.
You might wish to create your own iterators for the same reason you use methods instead of all public data in your classes: To encapsulate what's happening with an interface you can modify if you need to. As long as you typedef your T* to an iterator type this is probably not a significant issue. Additionally some algorithms may benefit from an iterator that's tagged with the iterator type, which you can't do for simple pointer types.
I am trying to implement or conceptually design a container that has contiguous memory but where the element order is unimportant (and that is exploited for insertion/removal of objects).
This is something that is similar to std::vector, but lifting the constraint that when an element is removed the relative order of the other elements is preserved, as in this case the last element can be put in place of the removed one.
I more or less know how to implement it (based on std::vector and some special back referenced iterator) but I am looking for a reference implementation to avoid reinventing the wheel.
I am familiar with Boost.Container, but I didn't find such container.
boost::container::flat_set is close, but it maintains the order, which is unnecessary. In some sense, I am looking for some sort of "boost::container::unordered_flat_set" or "unordered_vector".
This is the behavior that I expect:
unordered_flat_set<T> ufs(100); // allocates 100 elements
ufs.reserve(120);
unordered_flat_set<T>::iterator it = ...; // find something
ufs.erase(it); // overwrite last element to that position, destroy last element
ufs.insert(T{}); //add element at "end", only if necessary reallocate, keep buffer memory in multiples of 2 (or 1.6). Element order is not fundamental, can be altered completely by a call to "erase".
ufs.size(); // report size
Both erase and insert are O(1), (unless reallocation is necessary).
Is this a concept that is not already in standard or non-standard containers.
(Perhaps it is the concept of being unordered that doesn't play well with the current containers.
After all the only "unordered" currently is std::unordered_set and it is fairly new.)
This is a reference (very minimal) implementation, it is mainly to give a concrete realization of the concept I am looking for. In fact I am looking to see if the concept already exists to apply it to an existing base-code.
I am not trying to reinvent the wheel.
#include<iostream>
#include<vector>
template<class T>
class unordered_vector{
std::vector<T> impl_;
public:
unordered_vector(){}
void reserve(int i){impl_.reserve(i);}
struct iterator{
std::vector<T>* back_ptr;
int i;
T& operator*(){return back_ptr->operator[](i);}
iterator operator++(){++i; return *this;}
iterator operator--(){--i; return *this;}
bool operator==(iterator const& other) const{return back_ptr == other.back_ptr and i == other.i;}
bool operator!=(iterator const& other) const{return not(*this == other);}
};
int size(){return impl_.size();}
iterator erase(iterator it){
*it = it.back_ptr->last(); // should I use placement new here to not rely in customized (or not assignable object type)?
return it.back_ptr->erase(it.rbegin()); // I return this for compatibility, although there is no use for this
}
iterator insert(T t){
impl_.push_back(t); return {&impl_, size()-1};
}
iterator begin(){return {&impl_, 0};} // does an unordered container have a begin ?? ok, for compatibility, like std::unordered_set
iterator end(){return {&impl_, (int)impl_.size()};} // same question,
T& operator[](int i){return impl_[i];} // same question, if it is unordered v[i] has not a "salient" meaning.
};
int main(){
unordered_vector<double> uv;
uv.reserve(10);
uv.insert(1.1);
uv.insert(2.3);
uv.insert(5.4);
uv.insert(3.1);
std::cout << uv.size() << std::endl;
auto it = uv.begin();
assert( uv.begin() != uv.end());
assert( it != uv.end() );
for(auto it = uv.begin(); it != uv.end(); ++it){
std::cout << *it << std::endl;
}
}
Please see sfl library that I have recently updated to GitHub:
https://github.com/slavenf/sfl-library
It is C++11 header only library that offers flat ordered and unordered containers that store elements contiguously in memory. All containers meet requirements of Container, AllocatorAwareContainer and ContiguousContainer.
I have a custom vector container that internally stores item a linear array. Last night, I was trying to implement custom iterators for my class to be able to use them with STL algorithms. I have had some success that you can see in here:
Live example with custom iterators
While doing so, I discovered I can merely pass raw pointers to STL algorithm and they just seem to work fine. Here's the example without any iterators:
#include <cstddef>
#include <iostream>
#include <iterator>
#include <algorithm>
template<typename T>
class my_array{
T* data_;
std::size_t size_;
public:
my_array()
: data_(NULL), size_(0)
{}
my_array(std::size_t size)
: data_(new T[size]), size_(size)
{}
my_array(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
}
my_array(const T* first, const T* last){
size_ = last - first;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = first[i];
}
~my_array(){
delete [] data_;
}
const my_array<T>& operator=(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
return other;
}
const T& operator[](std::size_t idx) const {return data_[idx];}
T& operator[](std::size_t& idx) {return data_[idx];}
std::size_t size(){return size_;}
T* begin(){return data_;}
T* end(){return data_+size_;}
};
template<typename T>
void print(T t) {
std::cout << t << std::endl;
}
int main(){
typedef float scalar_t;
scalar_t list [] = {1, 3, 5, 2, 4, 3, 5, 10, 10};
my_array<scalar_t> a(list, list+sizeof(list)/sizeof(scalar_t));
// works!
for (scalar_t* it = a.begin(), *end = a.end();
it != end; ++it)
std::cout << ' ' << *it;
std::cout << std::endl;
// works!
std::for_each(a.begin(), a.end(), print<scalar_t>);
std::cout << std::endl;
// works!
my_array<int> b(a.size());
std::copy(a.begin(), a.end(), b.begin());
// works!
scalar_t* end = std::remove(a.begin(), a.end(), 5);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
std::random_shuffle(a.begin(), end);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
std::cout << "Counts of 3 in array = " << std::count(a.begin(), end, 3) << std::endl << std::endl;
// works!
std::sort(a.begin(), end);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
if (!std::binary_search(a.begin(), a.end(), 5))
std::cout << "Removed!" << std::endl;
return 0;
}
Live example without iterators
My questions here are the following:
Does this always work for containers that have linear storage? I know that this would not work for linked-lists for example.
If they do work in this situation, why should I ever go through the hassle of implementing iterators anyway? I know how iterators generalize my code and whatnot, but if this simple array is all I ever need then I don't see the point.
What are the negative issues of what I'm doing if this approach would always work? For one thing, I can see I'm breaking data encapsulation.
One of the features of iterators being based on operator-overloading, is that pointers are already random-access iterators. This was a big design win in the early days of STL, as it made it easier to use algorithms with existing code (as well as making the interface more familiar to programmers). It's perfectly reasonable to wrap an array, add typedef T* iterator; typedef const T* const_iterator, return &array[0] from your begin() and &array[size] from your end(), and then use your container with any iterator-based algorithm. As you already realise, this will work for any container where elements are contiguous in memory (such as an array).
You might implement 'real' iterators if:
You have a different-shaped container (such as a tree or list);
You want to be able to resize the array without invalidating the iterators;
You want to add debugging checks to your iterator use, for example to check if the iterator is used after being invalidated or after the container has been deleted, or to bounds-check;
You want to introduce type-safety, and make sure people can't accidentally assign an arbitrary T* to a my_array::iterator.
I'd say this last advantage alone is well worth writing a trivial wrapper class for. If you don't take advantage of C++'s type system by making different kinds of thing have different types, you might as well switch to Javascript :-)
Yes. See Effective STL, Item 16, which demonstrates with linear storage containers you can simply take the address of an item and work with that pointer as if it pointed to a simple array.
I think you answered your own question – you probably shouldn't, if you know the simple array is all you'll ever need.
Probably the biggest issue is just that – breaking data encapsulation. Consider whether or not an abstraction such as an explicit iterator type would buy you anything versus the cost.
Does this always work for containers that have linear storage?
Yes, the iterator concepts were designed so that pointers could act as iterators over arrays.
If they do work in this situation, why should I ever go through the hassle of implementing iterators anyway?
There's no good reason to define your own iterator type in this situation, unless you want to do something like bounds-checking which can't be done with a simple pointer.
One slight benefit would be that you could include nested typedefs for the iterator's traits, as some of the standard iterator types do; but using pointers these are available from std::iterator_traits<T*> anyway.
What are the negative issues of what I'm doing if this approach would always work? For one thing, I can see I'm breaking data encapsulation.
To make the interface more consistent with STL-style containers, you should define iterator and const_iterator types (typedef aliases for the pointers), and provide const overloads of begin and end; and perhaps cbegin and cend for C++11 compatiblity.
There are various other requirements that you might want to conform to; see section 23.2 of the C++ standard for the gory details. But in general, it's more important to make iterators conform to their requirements, since STL-style algorithms work with iterators rather than containers, and by using pointers you already conform to those requirements.
It happens that pointers provide the interface required of random access iterators (dereference, increment, addition, difference, etc) and can be treated just like iterators.
It should always work for containers with contiguous storage.
You might wish to create your own iterators for the same reason you use methods instead of all public data in your classes: To encapsulate what's happening with an interface you can modify if you need to. As long as you typedef your T* to an iterator type this is probably not a significant issue. Additionally some algorithms may benefit from an iterator that's tagged with the iterator type, which you can't do for simple pointer types.
I have two vector<T> in my program, called active and non_active respectively. This refers to the objects it contains, as to whether they are in use or not.
I have some code that loops the active vector and checks for any objects that might have gone non active. I add these to a temp_list inside the loop.
Then after the loop, I take my temp_list and do non_active.insert of all elements in the temp_list.
After that, I do call erase on my active vector and pass it the temp_list to erase.
For some reason, however, the erase crashes.
This is the code:
non_active.insert(non_active.begin(), temp_list.begin(), temp_list.end());
active.erase(temp_list.begin(), temp_list.end());
I get this assertion:
Expression:("_Pvector == NULL || (((_Myvec*)_Pvector)->_Myfirst <= _Ptr && _Ptr <= ((_Myvect*)_Pvector)->_Mylast)",0)
I've looked online and seen that there is a erase-remove idiom, however not sure how I'd apply that to a removing a range of elements from a vector<T>
I'm not using C++11.
erase expects a range of iterators passed to it that lie within the current vector. You cannot pass iterators obtained from a different vector to erase.
Here is a possible, but inefficient, C++11 solution supported by lambdas:
active.erase(std::remove_if(active.begin(), active.end(), [](const T& x)
{
return std::find(temp_list.begin(), temp_list.end(), x) != temp_list.end();
}), active.end());
And here is the equivalent C++03 solution without the lambda:
template<typename Container>
class element_of
{
Container& container;
element_of(Container& container) : container(container) {}
public:
template<typename T>
bool operator()(const T& x) const
{
return std::find(container.begin(), container.end(), x)
!= container.end();
}
};
// ...
active.erase(std::remove_if(active.begin(), active.end(),
element_of<std::vector<T> >(temp_list)),
active.end());
If you replace temp_list with a std::set and the std::find_if with a find member function call on the set, the performance should be acceptable.
The erase method is intended to accept iterators to the same container object. You're trying to pass in iterators to temp_list to use to erase elements from active which is not allowed for good reasons, as a Sequence's range erase method is intended to specify a range in that Sequence to remove. It's important that the iterators are in that sequence because otherwise we're specifying a range of values to erase rather than a range within the same container which is a much more costly operation.
The type of logic you're trying to perform suggests to me that a set or list might be better suited for the purpose. That is, you're trying to erase various elements from the middle of a container that match a certain condition and transfer them to another container, and you could eliminate the need for temp_list this way.
With list, for example, it could be as easy as this:
for (ActiveList::iterator it = active.begin(); it != active.end();)
{
if (it->no_longer_active())
{
inactive.push_back(*it);
it = active.erase(it);
}
else
++it;
}
However, sometimes vector can outperform these solutions, and maybe you have need for vector for other reasons (like ensuring contiguous memory). In that case, std::remove_if is your best bet.
Example:
bool not_active(const YourObjectType& obj);
active_list.erase(
remove_if(active_list.begin(), active_list.end(), not_active),
active_list.end());
More info on this can be found under the topic, 'erase-remove idiom' and you may need predicate function objects depending on what external states are required to determine if an object is no longer active.
You can actually make the erase/remove idiom usable for your case. You just need to move the value over to the other container before std::remove_if possibly shuffles it around: in the predicate.
template<class OutIt, class Pred>
struct copy_if_predicate{
copy_if_predicate(OutIt dest, Pred p)
: dest(dest), pred(p) {}
template<class T>
bool operator()(T const& v){
if(pred(v)){
*dest++ = v;
return true;
}
return false;
}
OutIt dest;
Pred pred;
};
template<class OutIt, class Pred>
copy_if_predicate<OutIt,Pred> copy_if_pred(OutIt dest, Pred pred){
return copy_if_predicate<OutIt,Pred>(dest,pred);
}
Live example on Ideone. (I directly used bools to make the code shorter, not bothering with output and the likes.)
The function std::vector::erase requires the iterators to be iterators into this vector, but you are passing iterators from temp_list. You cannot erase elements from a container that are in a completely different container.
active.erase(temp_list.begin(), temp_list.end());
You try to erase elements from one list, but you use iterators for second list. First list iterators aren't the same, like in second list.
I would like to suggest that this is an example of where std::list should be used. You can splice members from one list to another. Look at std::list::splice()for this.
Do you need random access? If not then you don't need a std::vector.
Note that with list, when you splice, your iterators, and references to the objects in the list remain valid.
If you don't mind making the implementation "intrusive", your objects can contain their own iterator value, so they know where they are. Then when they change state, they can automate their own "moving" from one list to the other, and you don't need to transverse the whole list for them. (If you want this sweep to happen later, you can get them to "register" themselves for later moving).
I will write an algorithm here now to run through one collection and if a condition exists, it will effect a std::remove_if but at the same time will copy the element into your "inserter".
//fwd iterator must be writable
template< typename FwdIterator, typename InputIterator, typename Pred >
FwdIterator copy_and_remove_if( FwdIterator inp, FwdIterator end, InputIterator outp, Pred pred )
{
for( FwdIterator test = inp; test != end; ++test )
{
if( pred(*test) ) // insert
{
*outp = *test;
++outp;
}
else // keep
{
if( test != inp )
{
*inp = *test;
}
++inp;
}
}
return inp;
}
This is a bit like std::remove_if but will copy the ones being removed into an alternative collection. You would invoke it like this (for a vector) where isInactive is a valid predicate that indicates it should be moved.
active.erase( copy_and_remove_if( active.begin(), active.end(), std::back_inserter(inactive), isInactive ), active.end() );
The iterators you pass to erase() should point into the vector itself; the assertion is telling you that they don't. This version of erase() is for erasing a range out of the vector.
You need to iterate over temp_list yourself and call active.erase() on the result of dereferencing the iterator at each step.