我浏览了这个页面,但我无法得到相同的原因。那里提到了
“更明智的是它根本不返回任何值并要求 客户端使用 front() 检查队列前面的值”
但是从 front() 检查元素还需要将该元素复制到左值中。例如在这段代码中
std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);
/* here temporary will be created on RHS which will be assigned to
result, and in case if returns by reference then result will be
rendered invalid after pop operation */
result = myqueue.front(); //result.
std::cout << ' ' << result;
myqueue.pop();
第五行 cout 对象首先创建 myqueue.front() 的副本,然后将其分配给 result。那么,有什么区别呢,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
}
如果 T 的复制构造函数在返回时抛出异常,则说明您已经更改了队列的状态(在我的幼稚实现中为
top_position
),并且该元素已从队列中删除(并且不返回)。出于所有意图和目的(无论您如何在客户端代码中捕获异常),队列顶部的元素都会丢失。
当您不需要弹出的值时(即它创建了没有人会使用的元素的副本),这种实现也是低效的。
这可以通过两个单独的操作(
void pop
和const T& front()
)安全有效地实施。
您链接到的页面回答了您的问题。
引用整个相关部分:
有人可能想知道为什么 pop() 返回 void,而不是 value_type。也就是说,为什么必须使用 front() 和 pop() 来检查和删除队列前面的元素,而不是将两者组合在一个成员函数中?事实上,这样的设计是有充分理由的。如果 pop() 返回前面的元素,则必须按值返回而不是按引用返回:按引用返回会创建一个悬空指针。然而,按值返回的效率很低:它至少涉及一次冗余的复制构造函数调用。由于 pop() 不可能以既高效又正确的方式返回值,所以更明智的做法是根本不返回任何值,并要求客户端使用 front() 检查值队列的前面。
C++ 的设计考虑了效率,而不是程序员必须编写的代码行数。
pop 无法返回对被删除值的引用,因为它正在从数据结构中删除,那么该引用应该引用什么?它可以按值返回,但是如果 pop 的结果没有存储在任何地方怎么办?然后时间就浪费在不必要的复制值上。
从 C++11 开始,可以使用移动语义实现所需的行为。就像
pop_and_move
。因此复制构造函数不会被调用,性能仅取决于移动构造函数。
对于当前的实施,这是有效的:
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;
你完全可以做到这一点:
std::cout << ' ' << myqueue.front();
或者,如果您想要变量中的值,请使用引用:
const auto &result = myqueue.front();
if (result > whatever) do_whatever();
std::cout << ' ' << result;
接下来:“更明智”这个措辞是“我们研究了使用模式并发现更需要拆分”的主观形式。 (放心:C++ 语言的发展并不轻松……)