【问题标题】:Will std::queue front take front element out of the line?std::queue front 会将前面的元素排除在外吗?
【发布时间】:2010-11-09 12:56:29
【问题描述】:

std::queue::front 会取消前面的元素吗?如果没有怎么删除呢?

【问题讨论】:

    标签: c++ queue std


    【解决方案1】:

    有一个获取元素的函数,另一个用于删除元素的函数:

    typedef queue<MyClass> MyQueue;
    MyQueue q;
    q.push(MyClass(42));
    // ...
    MyClass const& rx = q.front();
    rx.print();
    
    MyClass x = q.front(); // Copies the front element to a fresh object
    q.pop(); // From this point, rx is a dangling reference
    assert(x == MyClass(42));
    

    基本原理:如果只有一个 pop 函数返回前面的元素,则不可能获得对前面元素的引用,因为它会从队列中删除。如果您只想在丢弃之前读取一个巨大的元素,那么您肯定不希望您的代码执行复制。

    编辑:一个更根本的原因是拥有两个功能意味着用户负责制作副本。假设只有一个pop 函数:如果复制构造函数(pop 内部)抛出异常会发生什么? (参见@Steve Jessop 的评论)

    【讨论】:

    • ... 即使您确实想要复制,也无法在提供强大的异常保证的同时按值返回。对调用者左值的复制发生在 对象已从队列中删除之后,因此如果复制 ctor 或复制分配(无论在该特定情况下是什么)抛出异常,则队列已经被弹出。
    • @Steve:你是对的。为了完整起见,应该提到异常安全。
    • @Alexandre:正如史蒂夫所强调的那样,基本原理是关于异常保证,而不是关于interface,因为您可以同时拥有front 和返回副本的pop。要么是这种行为,要么是要求复制构造函数不能抛出。
    • @Alexandre C. 两个副本不会这样做。不仅要强制要求 RVO,还要强制要求一种 RVO 形式,它允许 copy-assignment 就地,而不仅仅是复制构造,以使 MyClass x; x = q.pop(); 异常安全.正如我们所知,这在 C++ 中是不可行的。一个更简单的替代方法是pop 采用非常量引用参数,并在修改队列之前将前端对象复制到该参数中。这很容易成为异常安全的,AFAIK 不提供它的原因只是它是front()pop() 的简单组合,所以可以自己动手做。
    • @Alexandre:实际上,这可以通过另一个接口queue.pop(item) 来完成,使用赋值而不是复制构造。我猜这不太惯用。
    【解决方案2】:

    不,它只是返回对前面元素的引用。如果您需要取出元素,请使用pop()。有关详细信息,请参阅std::queue 参考。

    【讨论】:

      【解决方案3】:

      队列前端操作的类型定义。

      value_type& queue::front ()
      const value_type& queue::front () const
      

      两种形式都返回队列的下一个元素。调用者必须确保队列包含一个元素(size()>0);否则,行为未定义。非常量队列的第一种形式返回一个引用。因此,您可以修改队列中的下一个元素。由您决定这是否是好的风格。

      使用 pop 删除它。它从队列中删除下一个元素。下一个元素是最先插入的元素(在队列中的所有其他元素之前)。这个函数没有返回值。要处理下一个元素,您必须先调用 front()。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-13
        • 2013-12-05
        • 2014-10-13
        • 1970-01-01
        • 2015-10-11
        • 1970-01-01
        • 2019-06-16
        • 2016-03-31
        相关资源
        最近更新 更多