使用2方法提取容器中的数据(pop_front和front)

时间:2013-09-24 00:17:35

标签: c++ forward-list

(抱歉我的英语不好!) 嗨,我正在学习工业计算。这是我的第五个任期。在我的一门课程中,老师要求我们在c中写一个班级'List'(仅向前,一个ptr到下一个元素而不是前一个元素)。我做了一个简单的'extract'方法,它返回一个value_type并删除第一个元素,但我的老师说,如果复制构造函数抛出一个异常,那么该值将因为已被提取而丢失。我期待std :: forward_list,我已经看到stl提供了一个提取方法和一个访问最后一个元素的方法(pop_front()和front())。 我不明白为什么我们不能在一个方法中做到这一点? 我写了这段代码:

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;
   }
}

我还使用nothrow_t参数创建了一个方法提取,它不会复制任何东西(返回void),因此我们可以“强制”提取。 为什么stl没有这样做?做“auto v = something.pop();”会很高兴。 ! 我的版本是否安全?如果我们真的关心可以在复制构造函数中抛出的异常,并且我们真的想继续使用AND来保存数据,那么我们不能简单地尝试捕获'pop'方法吗?

谢谢你的帮助!

2 个答案:

答案 0 :(得分:0)

STL使它成为两个操作,因为front()函数返回一个引用,而不是一个值,以消除双重副本。在返回项目时从列表中删除项目需要按值返回,否则该对象已经超出范围。

答案 1 :(得分:0)

  

我不明白为什么我们不能用一种方法来做呢?

需要两个操作来提供强大的异常保证 - 也就是说,如果在任何时候抛出异常,则不应更改容器。

您的提案auto v = something.pop()必须按顺序执行以下三项操作:

  • 从容器中删除元素;
  • 从函数中返回该元素;
  • 使用返回值初始化v

如果最后一个阶段抛出异常,那么该元素将从容器中删除并丢失。您尝试使用try...catch构造修复它将无济于事:从函数返回后将抛出异常,因此函数中的处理程序不会捕获该异常。

使用STL样式的界面分两个阶段进行,顺序是:

  • 处理对容器元素的引用;
  • 从容器中删除元素。

现在,如果处理抛出异常,该元素将保留在容器中并且不会丢失。

现在,随着语言中添加了移动语义,您可以实现您的版本,并要求元素在移动时不会抛出。这是一个相当合理的要求,已经在C ++ 11容器上进行了一些操作。但这种情况并没有发生,我怀疑这种改变只是为了一点点便利。

  

如果我们真的关心可以在复制构造函数中抛出的异常,并且我们真的想继续使用AND来保存数据,那么我们不能简单地尝试捕获'pop'方法吗?

我们可以;但这比提供异常安全的界面更不方便,也更容易出错。