C++ 为什么';t std::queue::pop返回值。?

C++ 为什么';t std::queue::pop返回值。?,c++,stl,C++,Stl,我经历了这些,但我无法得到同样的原因。有人提到 “更明智的做法是,它根本不返回任何价值,而是要求 客户端使用front()检查队列前面的值“ 但是从front()检查一个元素也需要在左值中复制该元素。例如,在这个代码段中 std::queue<int> myqueue; int myint; int result; std::cin >> myint; myqueue.push (myint); std::queue myqueue; int-myint; int结果;

我经历了这些,但我无法得到同样的原因。有人提到

“更明智的做法是,它根本不返回任何价值,而是要求 客户端使用front()检查队列前面的值“


但是从front()检查一个元素也需要在左值中复制该元素。例如,在这个代码段中

std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);
std::queue myqueue;
int-myint;
int结果;
std::cin>>myint;
myqueue.push(myint);
/*此处将在RHS上创建临时文件,并将其分配给结果,以防 若通过引用返回,则pop操作后结果将呈现为无效*/

result = myqueue.front();  //result.
std::cout << ' ' << result;
myqueue.pop();
result=myqueue.front()//结果。

std::cout您完全可以这样做:

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

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

对于当前的实现,这是有效的:

int &result = myqueue.front();
std::cout << result;
myqueue.pop();
由于引用不再有效,以下代码可能会崩溃:

int &result = myqueue.pop();
std::cout << result;
然后,您需要复制此代码才能正常工作,这会降低效率:

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

std::cout您链接到的页面回答您的问题

引用整个相关章节:

有人可能想知道为什么pop()返回void,而不是value\u type。也就是说,为什么必须使用front()和pop()来检查和删除队列前面的元素,而不是在单个成员函数中组合这两个元素?事实上,这种设计有很好的理由。如果pop()返回front元素,则必须按值而不是按引用返回:按引用返回将创建一个悬空指针。然而,按值返回效率很低:它至少涉及一个冗余的复制构造函数调用。由于pop()不可能以既高效又正确的方式返回值,因此更明智的做法是完全不返回值,并要求客户端使用front()检查队列前端的值

C++的设计考虑了效率,超过了程序员必须编写的代码行数

那么,有什么区别,pop函数可以做同样的事情

它确实可以做同样的事情。之所以没有,是因为返回popped元素的pop在存在异常的情况下是不安全的(必须按值返回,从而创建副本)

考虑一下这个场景(用一个幼稚/虚构的pop实现来说明我的观点):

模板
类队列{
T*元素;
标准:尺寸与顶部位置;
//这里的东西
T pop()
{
自动x=元素[顶部位置];
//TODO:在此处调用元素[top_position]的析构函数
--top_position;//在此处更改队列状态
return x;//调用T(const T&),它可能抛出
}
如果T的复制构造函数在返回时抛出,则表示您已经更改了队列的状态(
top\u position
,在我的简单实现中),并且元素从队列中移除(并且没有返回)。出于所有目的(无论您如何在客户端代码中捕获异常),队列顶部的元素都将丢失

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


通过两个单独的操作(
void pop
const T&front()
)可以安全高效地实现这一点。

我认为最好的解决方案是添加如下内容

std::queue::pop_and_store(value_type& value);
其中value将接收弹出的值


它的优点是可以使用移动赋值操作符来实现,而使用front+pop将生成一个副本。

从C++11开始,可以使用移动语义来归档所需的行为。例如
pop\u和\u move
。因此不会调用复制构造函数,性能将仅取决于移动构造函数

因为这样实现了(即,代码>空格STD::Que::Popy[];)。问题已经得到了解答,但作为旁注:如果您真的想要一个返回的POP,那么它可以很容易地用一个免费的函数实现:您的链接是STL文档。但是您正在询问C++标准库。“但是从
front()
检查元素也需要在左值中复制该元素"-不,不返回。
front
返回一个引用,而不是一个值。您可以检查它引用的值,而不复制它。@KeminZhou您描述的模型需要一个副本。可能。如果您想多路复用队列的使用,那么是的,您必须在释放队列上的锁之前复制一个副本。但是,如果您只关心separating输入和输出,则不需要锁来检查前端。您可以等待锁,直到用完它,然后需要调用
pop()
。如果使用
std::queue
,则不必担心
front()
提供的引用被
push()无效
。但您必须了解您的使用模式,并记录您的约束。真正的原因是异常安全。没有安全的方法可以对堆栈进行“事务处理”(元素保留在堆栈上,或者返回给您)如果
pop
返回,则返回操作可能会导致异常。它显然必须在返回元素之前删除该元素,然后如果有东西抛出该元素,则该元素可能会不可挽回地丢失。此问题是否仍然适用于f.i.noexcept move构造函数?(当然,0份拷贝比两次移动更有效,但这可能为异常安全、高效组合的front+pop打开大门)@peppe,如果
value_type pop();
int result = myqueue.pop();
std::cout << result;
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
    }
std::queue::pop_and_store(value_type& value);