Почему не std:: queue:: pop возвращает значение.?
Я просмотрел эту страницу, но я не могу понять причину этого. Там упоминается, что
"более разумно, чтобы он не возвращал никакой ценности и требовал клиентам использовать front() для проверки значения в передней части очереди"
Но для проверки элемента из front() также требуется, чтобы этот элемент был скопирован в lvalue. Например, в этом сегменте кода
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 могла бы сделать то же самое.
Ответы
Ответ 1
Итак, какая разница, функция 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()
).
Ответ 2
Страница, с которой вы связались, отвечает на ваш вопрос.
Чтобы процитировать весь раздел:
Можно спросить, почему pop() возвращает void вместо value_type. То есть, почему нужно использовать функции front() и pop() для проверки и удаления элемента в передней части очереди вместо объединения двух в одну функцию-член? На самом деле, есть веская причина для этого дизайна. Если pop() вернул передний элемент, ему пришлось бы возвращать по значению, а не по ссылке: return by reference создавал бы висячий указатель. Однако возврат по значению неэффективен: он включает по крайней мере один избыточный вызов конструктора копии. Так как невозможно, чтобы pop() возвращало значение таким образом, чтобы быть как эффективным, так и правильным, более разумно для него вообще не возвращать значение и требовать от клиентов использовать front() для проверки значения в фронт очереди.
С++ разработан с учетом эффективности, над количеством строк кода, которые программист должен написать.
Ответ 3
pop не может вернуть ссылку на удаляемое значение, поскольку оно удаляется из структуры данных, так что ссылка должна ссылаться? Он может вернуться по значению, но что, если результат поп-музыки нигде не сохраняется? Тогда время тратится впустую без необходимости излишнего копирования значения.
Ответ 4
С текущей реализацией это действительно:
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;
Ответ 5
Начиная с С++ 11 можно было бы архивировать желаемое поведение, используя семантику перемещения. Как pop_and_move
. Поэтому конструктор копирования не будет вызываться, а производительность будет зависеть только от конструктора перемещения.
Ответ 6
Вы можете полностью сделать это:
std::cout << ' ' << myqueue.front();
Или, если вы хотите получить значение в переменной, используйте ссылку:
const auto &result = myqueue.front();
if (result > whatever) do_whatever();
std::cout << ' ' << result;
Кроме того: формулировка "более разумная" является субъективной формой "мы изучали шаблоны использования и находили больше потребности в расколе". (Будьте уверены: язык С++ не развивается легко...)
Ответ 7
Я думаю, лучшим решением было бы добавить что-то вроде
std::queue::pop_and_store(value_type& value);
где значение получит всплывающее значение.
Преимущество заключается в том, что он может быть реализован с использованием оператора присваивания переходов, а использование функции front + pop сделает копию.