Быстрый фон
Я - Java-разработчик, который играл вокруг с C++ в мое свободное/скучающее время.
Предисловие
В C++ Вы часто видите, что поп берет аргумент ссылкой:
void pop(Item& removed);
Я понимаю, что хорошо "заполнить" параметр с тем, что Вы удалили. Это полностью имеет смысл мне. Таким образом, человек, который попросил удалять главный объект, может взглянуть на то, что было удалено.
Однако, если бы я должен был сделать это в Java, то я сделал бы что-то вроде этого:
Item pop() throws StackException;
Таким образом, после поп мы возвращаемся также: ПУСТОЙ УКАЗАТЕЛЬ в результате Объект или исключение был бы брошен.
Мой учебник C++ показывает мне пример выше, но я вижу много реализаций стека, берущих аргументы (stl стек, например).
Вопрос
Как нужно реализовать поп-функцию в C++?
Премия
Почему?
Чтобы ответить на вопрос: вам не следует реализовывать функцию pop в C ++, поскольку она уже реализована в STL. Адаптер контейнера std :: stack
предоставляет метод top
для получения ссылки на верхний элемент в стеке и метод pop
для удаления верхнего элемента. . Обратите внимание, что метод pop
сам по себе не может использоваться для выполнения обоих действий, как вы просили.
Почему это должно быть сделано именно так?
top
берет на себя одну ответственность, а pop
- другую. Любой код, желающий получить копию элемента, может сделать это без дополнительных затрат:
Foo f(s.top());
s.pop();
Кроме того, это обсуждение может быть интересным.
Если вы собирались реализовать pop для возврата значения, не имеет большого значения, возвращаете ли вы его по значению или записываете его в выходной параметр. Большинство компиляторов реализуют RVO , который оптимизирует метод возврата по значению, чтобы он был столь же эффективным, как метод копирования в параметры. Просто имейте в виду, что любой из них, вероятно, будет менее эффективным, чем изучение объекта с помощью top () или front (), поскольку в этом случае копирование абсолютно не выполняется.
Единственная причина, по которой я могу использовать этот синтаксис в C ++:
void pop(Item& removed);
, - это если вы беспокоитесь о том, что будут иметь место ненужные копии.
если вы вернете элемент
, он может потребовать дополнительную копию объекта, что может быть дорогостоящим.
На самом деле компиляторы C ++ очень хороши в копировании и почти всегда реализуют оптимизацию возвращаемого значения (часто даже при компиляции с отключенной оптимизацией), что делает вопрос спорным и может даже означать простой «возврат по значению» версия в некоторых случаях становится быстрее .
Но если вы занимаетесь преждевременной оптимизацией (если вы беспокоитесь о том, что компилятор может не оптимизировать копию, даже если на практике он сделает это ), вы может выступать за "возвращение" параметров путем присвоения ссылочным параметрам.
Дополнительная информация здесь
ИМО, хорошая сигнатура для эквивалента функции Java pop
в C ++ будет выглядеть примерно так:
boost::optional<Item> pop();
Использование типов параметров - лучший способ вернуть то, что может быть, а может и нет.
Использование C ++ 0x снова усложняет задачу.
As
stack.pop(item); // move top data to item without copying
позволяет эффективно перемещать верхний элемент из стека. В то время как
item = stack.top(); // make a copy of the top element
stack.pop(); // delete top element
не допускает такой оптимизации.
Проблема подхода Java заключается в том, что его метод pop ()
имеет как минимум два эффекта: удаление элемента и возврат элемент. Это нарушает принцип единственной ответственности при разработке программного обеспечения, что, в свою очередь, открывает двери для сложностей проектирования и других проблем. Это также влечет за собой снижение производительности.
С точки зрения STL идея состоит в том, что иногда, когда вы pop ()
, вас не интересует всплывающий элемент. Вам просто нужен эффект удаления верхнего элемента. Если функция возвращает элемент, а вы его игнорируете, то это потраченная впустую копия.
Если вы предоставляете две перегрузки, одна из которых принимает ссылку, а другая - нет, вы позволяете пользователю выбирать, заинтересован ли он (или она) в возвращаемом элементе или нет. Производительность звонка будет оптимальной.
STL не перегружает функции pop ()
, а скорее разделяет их на две функции: back ()
(или top ()
в случай адаптера std :: stack
) и pop ()
. Функция back ()
просто возвращает элемент, а функция pop ()
просто удаляет его.