How to transfer std :: unique_ptr <> from one STL container to another?

Problem

I have a template container MyContainer<std::unique_ptr<Foo>> that has a member std::deque<T> and std::vector<T> .

Inside the send_to_purgatory_if( predicate ) method, I would like to look at all the elements in m_taskdq and move the elements from m_taskdq to m_purgatory if the predicate evaluates to true.

Questions

I have two problems I'm struggling with:

  • my iterator it gets hashing if I remove items from m_taskdq from a loop
  • I am worried about the state of std::unique_ptr<> , if I make the transition in two stages (problem lines 1 and 2 - on line 2, I think that std::unique_ptr<> , which it points to is undefined?)

How do 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; }; 
+4
source share
1 answer

This is really a C ++ 98 question with a red herring regarding the semantics of movement. The first thing to ask is to do it in C ++ 98:

std::deque::erase(iterator) returns an iterator that refers to the element after erasing. So first get started:

  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's easy to get it working with the C ++ 11 relocation 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; } } 

unique_ptr moved from taskdq becomes unique_ptr null after emplace_back , and then erased in the next line. No harm, no foul.

When there is an erase , returning from erase does a good job of increasing the iterator. And when there is no erase , the normal increment of the iterator is in order.

+11
source

Source: https://habr.com/ru/post/1400919/


All Articles