我经历了这个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功能可以做同样的事情。
答案 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 pop
和const 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可以复制。