为什么std :: queue :: pop没有返回值.?

cbi*_*der 102 c++ stl

我浏览了这个页面,但我无法得到同样的理由.在那里提到了

"它根本不返回任何值并要求客户端使用front()来检查队列前面的值更为明智"

但是检查front()中的元素也需要将该元素复制到左值.例如,在此代码段中

std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);
Run Code Online (Sandbox Code Playgroud)

/*这里临时将在RHS上创建,它将被分配给结果,如果通过引用返回,则在弹出操作后结果将变为无效*/

result = myqueue.front();  //result.
std::cout << ' ' << result;
myqueue.pop();
Run Code Online (Sandbox Code Playgroud)

在第五行cout对象首先创建myqueue.front()的副本然后将其分配给结果.那么,最重要的是,pop功能可以做同样的事情.

utn*_*tim 92

那么,最重要的是,pop功能可以做同样的事情.

它确实可以做同样的事情.它没有的原因是因为返回弹出元素的pop在出现异常时是不安全的(必须按值返回并因此创建副本).

考虑一下这个场景(用一个天真的/编造的pop实现来说明我的观点):

template<class T>
class queue {
    T* elements;
    std::size_t top_position;
    // stuff here
    T pop()
    {
        auto x = elements[top_position];
        // TODO: call destructor for elements[top_position] here
        --top_position;  // alter queue state here
        return x;        // calls T(const T&) which may throw
    }
Run Code Online (Sandbox Code Playgroud)

如果T的复制构造函数在返回时抛出,则您已经更改了队列的状态(top_position在我的天真实现中),并且元素将从队列中删除(并且不会返回).对于所有意图和目的(无论您如何捕获客户端代码中的异常),队列顶部的元素都将丢失.

当您不需要弹出值时(即,它会创建一个没人会使用的元素的副本),此实现也是低效的.

这可以通过两个单独的操作(void popconst T& front())安全有效地实现.

  • C++ 11注意:如果T有一个廉价的noexcept移动构造函数(通常是放在堆栈中的对象类型的情况),那么按值返回是有效且异常安全的. (30认同)
  • @utnapistim:事实上的"pop"操作一直是从堆栈中取出顶部元素并返回它.当我第一次遇到STL堆栈时,至少可以说,我很惊讶"pop"没有返回任何东西.例如,参见[维基百科](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Array). (12认同)
  • 但为什么它被称为"流行音乐"?这是违反直觉的.它可以命名为`drop`,然后很明显,每个人都不会弹出元素,而是放弃它... (10认同)
  • @DavidRodríguez-dribeas:我不是在暗示任何改变,我的观点是,所提到的一些缺点不再是C++ 11的问题. (9认同)

小智 32

您链接的页面会回答您的问题.

引用相关的整个部分:

有人可能想知道为什么pop()返回void而不是value_type.也就是说,为什么必须使用front()和pop()来检查和删除队列前面的元素,而不是将它们组合在一个成员函数中?事实上,这种设计有充分的理由.如果pop()返回前面的元素,它将不得不按值而不是通过引用返回:按引用返回将创建一个悬空指针.然而,按值返回是低效的:它涉及至少一个冗余复制构造函数调用.因为pop()不可能以高效和正确的方式返回值,所以更不明智地返回任何值并要求客户端使用front()来检查值队列的前面.

在编程人员必须编写的代码行数上,C++的设计考虑了效率.

  • 也许,但真正的原因是,对于返回值的`pop`版本,不可能实现异常安全版本(具有强保证). (15认同)

Nei*_*irk 5

pop不能返回对被删除的值的引用,因为它正从数据结构中删除,那么引用应该引用什么?它可以按值返回,但是如果pop的结果没有存储在任何地方呢?然后浪费时间不必要地复制价值.

  • 真正的原因是异常安全.如果`pop`返回并且返回的行为可能导致异常,则没有安全的方法来与堆栈进行"事务"(元素保留在堆栈上,或者它返回给你).显然必须在它返回之前删除该元素,然后如果某些东西抛出该元素可能会不可挽回地丢失. (4认同)