Question

( sorry for my bad english! ) Hi, I'm studying in industrial computing. This is my fifth term. In one of my course the teacher asked us to write a class 'List' ( forward only, a ptr to the next element but not the previous ) in c . I've done a simple 'extract' method which return a value_type and removes the first element but my teacher said that, if the copy constructor throws an exception, the value would be lost because it has been extracted. I've look to std::forward_list and i've seen that the stl offers a method to extract and a method to acces the last element ( pop_front() and front() ). I don't understand why do we can't do it in a single method ? I've wrote this code :

value_type extract()
{
   if( empty() )
     throw EmptyList();
   std::unique_ptr< Node > p = m_Head;
   if( m_Head == m_Last )
     m_Last = nullptr;
   m_Head = m_Head->m_Next;
   try
   {
       return p->m_Value;
   }
   catch( ... )
   {
       m_Head = p.release();
       if( !m_Last )
          m_Last = m_Head;
       throw;
   }
}

I've also made a method extract with a nothrow_t parameter which doesn't copy anything ( return void ) so we can 'force' the extraction. Why does the stl isn't doing this ? It would be nice to do "auto v = something.pop();" ! Does my version is safe? If we realy care about an exception that can be throw in the copy constructor and we realy want to continue AND to keep the data, can't we simply try catch around the 'pop' method ?

Thank for you help!

Was it helpful?

Solution

I don't understand why do we can't do it in a single method ?

The two operations are needed to give a strong exception guarantee - that is, if an exception is thrown at any time, the container should not be changed.

Your proposal, auto v = something.pop(), has to do three things in order:

  • Remove an element from the container;
  • Return that element from the function;
  • Initialise v with the returned value.

If the final stage throws an exception, then the element will have been removed from the container and lost. Your attempt to fix that with a try...catch construct won't help: the exception will be thrown after returning from the function, and so will not be caught by a handler in the function.

Doing it in two stages with an STL-style interface, the order is instead:

  • Process a reference to the container element;
  • Remove the element from the container.

Now if the processing throws an exception, the element remains in the container and is not lost.

These days, with move semantics added to the language, you could implement your version, with a requirement that elements do not throw when moved. That's a fairly reasonable requirement, already made by some operations on C++11 containers. But that hasn't happened, and I doubt that such a change would be made just for a minor convenience.

If we realy care about an exception that can be throw in the copy constructor and we realy want to continue AND to keep the data, can't we simply try catch around the 'pop' method ?

We could; but that's less convenient, and much more error-prone, than providing an exception-safe interface.

OTHER TIPS

The STL makes it two operations because the front() function returns a reference, not a value, to eliminate double copies. Removing the item from the list while returning the item would require returning by value otherwise the object will have already gone out of scope.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top