Почему не 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 сделает копию.