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

时间:2014-07-30 11:29:47

标签: c++ stl

我经历了这个page,但我无法得到相同的理由。在那里提到

  

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

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

std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);

/ *这里临时将在RHS上创建,将分配给结果,以防万一  如果通过引用返回,那么在弹出操作* /

之后结果将变为无效
result = myqueue.front();  //result.
std::cout << ' ' << result;
myqueue.pop();

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

7 个答案:

答案 0 :(得分:82)

  

那么,最重要的是,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
    }

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

如果您不需要弹出值(即它会创建一个没人会使用的元素的副本),这种实现效率也很低。

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

答案 1 :(得分:30)

您链接的页面可以回答您的问题。

引用相关的整个部分:

  

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

C ++在设计时必须考虑到程序员必须编写的代码行数。

答案 2 :(得分:5)

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

答案 3 :(得分:1)

使用当前实现,这是有效的:

int &result = myqueue.front();
std::cout << result;
myqueue.pop();

如果pop会返回一个引用,如下所示:

value_type& pop();

然后以下代码可能崩溃,因为引用不再有效:

int &result = myqueue.pop();
std::cout << result;

另一方面,如果它会直接返回一个值:

value_type pop();

然后你需要复制一下这段代码才能正常工作,效率较低:

int result = myqueue.pop();
std::cout << result;

答案 4 :(得分:1)

从C ++ 11开始,可以使用移动语义归档所需的行为。像pop_and_move一样。因此不会调用复制构造函数,性能将仅取决于移动构造函数。

答案 5 :(得分:0)

你完全可以这样做:

std::cout << ' ' << myqueue.front();

或者,如果您想要变量中的值,请使用引用:

const auto &result = myqueue.front();
if (result > whatever) do_whatever();
std::cout << ' ' << result;

接下来:措辞更明智&#39;是一种主观形式的“我们研究了使用模式,发现更多需要分裂”。 (请放心:C ++语言并没有轻易发展......)

答案 6 :(得分:0)

我认为最好的解决方案是添加类似

的内容
std::queue::pop_and_store(value_type& value);

其中value将收到弹出值。

优点是可以使用移动赋值运算符实现,而使用front + pop可以复制。