I have a template container MyContainer<std::unique_ptr<Foo>>
which has a std::deque<T>
and a std::vector<T>
member.
Inside method, send_to_purgatory_if( predicate )
, I would like to look at all items in m_taskdq
and move items from m_taskdq
to m_purgatory
, if the predicate evaluates to true.
I have two issues that I'm struggling with:
it
gets trashed if I remove items from m_taskdq from inside the loopstd::unique_ptr<>
if I do the move in two steps (problem lines 1 and 2 - by line 2, I think the std::unique_ptr<>
pointed to by it
is undefined?)How should I fix this code?
template <typename T>
class MyContainer
{
typedef std::function<bool(T&)> PREDICATE;
void send_to_purgatory_if( PREDICATE p )
{
// bad code -------------------------------------
for( auto it=m_taskdq.begin(); it!=m_taskdq.end(); ++it )
{
if ( p( *it ) )
{
m_purgatory.emplace_back( move( *it )); // problem line 1
m_taskdq.erase( it ); // problem line 2
}
}
// end bad code ---------------------------------
}
std::deque< T > m_taskdq;
std::vector< T > m_purgatory;
};
This is really a C++98 question, with a red-herring concerning move semantics. The first thing to ask is how to do this in C++98:
std::deque::erase(iterator)
returns an iterator
that refers to the element after the one erased. So get that working first:
void send_to_purgatory_if( PREDICATE p )
{
for( auto it=m_taskdq.begin(); it!=m_taskdq.end();)
{
if ( p( *it ) )
{
m_purgatory.emplace_back(*it);
it = m_taskdq.erase(it);
}
else
++it;
}
}
And now it is easy to make it work with C++11 move semantics:
void send_to_purgatory_if( PREDICATE p )
{
for( auto it=m_taskdq.begin(); it!=m_taskdq.end();)
{
if ( p( *it ) )
{
m_purgatory.emplace_back(std::move(*it));
it = m_taskdq.erase(it);
}
else
++it;
}
}
The unique_ptr
moved from in taskdq
becomes a null unique_ptr
after the emplace_back
, and then it gets erased in the next line. No harm, no foul.
When there is an erase
, the return from the erase
does a good job at incrementing the iterator. And when there is no erase
, a normal iterator increment is in order.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With