Почему pop () должен принимать аргумент? - PullRequest
9 голосов
/ 03 мая 2010

Быстрый фон
Я Java-разработчик, который в свое свободное / скучающее время играл с C ++.

Предисловие
В C ++ вы часто видите, что pop принимает аргумент по ссылке:

void pop(Item& removed);

Я понимаю, что приятно "заполнить" параметр тем, что вы удалили. Это полностью имеет смысл для меня. Таким образом, человек, который попросил удалить верхний элемент, может посмотреть, что было удалено.

Однако, если бы я делал это на Java, я бы сделал что-то вроде этого:

Item pop() throws StackException;

Таким образом, после всплывающего окна мы возвращаем либо: NULL, в результате выдается Item или исключение.

В моем учебнике по C ++ показан пример, приведенный выше, но я вижу множество реализаций стека без аргументов (например, стек stl ).

Вопрос
Как реализовать поп-функцию в C ++?

Бонус
Почему?

Ответы [ 5 ]

26 голосов
/ 03 мая 2010

Чтобы ответить на вопрос: вы не должны реализовывать функцию pop в C ++, поскольку она уже реализована в STL. Контейнерный адаптер std::stack предоставляет метод top для получения ссылки на верхний элемент в стеке и метод pop для удаления верхнего элемента. Обратите внимание, что один метод pop не может использоваться для выполнения обоих действий, как вы и просили.

Зачем это нужно делать?

  1. Исключительная безопасность: Херб Саттер дает хорошее объяснение проблемы в ПОЛУЧИЛ # 82 .
  2. Принцип единоличной ответственности: также упоминается в GotW # 82. top берет на себя одну ответственность, а pop - другую.
  3. Не платите за то, что вам не нужно: Для некоторого кода может быть достаточно проверить верхний элемент и затем извлечь его, даже не делая (потенциально дорогую) копию элемента , (Это упоминается в документации SGI STL .)

Любой код, который хочет получить копию элемента, может сделать это без дополнительных затрат:

Foo f(s.top());
s.pop();

Также эта дискуссия может быть интересной.

Если вы собираетесь реализовать pop для возврата значения, не имеет большого значения, возвращаете ли вы значение или записываете его в выходной параметр. Большинство компиляторов реализуют RVO , что оптимизирует метод возврата по значению так, чтобы он был таким же эффективным, как метод копирования в параметр. Просто имейте в виду, что любой из них, вероятно, будет менее эффективным, чем проверка объекта с помощью top () или front (), поскольку в этом случае копирование абсолютно не выполняется.

4 голосов
/ 03 мая 2010

Проблема с подходом Java заключается в том, что его метод pop() имеет как минимум два эффекта: удаление элемента и возврат элемента. Это нарушает принцип единой ответственности при разработке программного обеспечения, что, в свою очередь, открывает двери для сложностей проектирования и других проблем. Это также подразумевает снижение производительности.

С точки зрения STL идея заключается в том, что иногда, когда вы pop() не интересуетесь предметом, выскочил. Вы просто хотите эффект удаления верхнего элемента. Если функция возвращает элемент, а вы игнорируете его, то это потерянная копия.

Если вы предоставляете две перегрузки, одна из которых принимает ссылку, а другая - нет, вы позволяете пользователю выбирать, заинтересован ли он (или она) в возвращаемом элементе или нет. Производительность звонка будет оптимальной.

STL не перегружает функции pop(), а разделяет их на две функции: back() (или top() в случае std::stack адаптера) и pop(). Функция back() просто возвращает элемент, а функция pop() просто удаляет его.

1 голос
/ 03 мая 2010

Использование C ++ 0x снова усложняет задачу.

Как

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

не позволяет такие оптимизации.

0 голосов
/ 03 мая 2010

IMO, хорошая подпись для эквивалента функции Java pop в C ++ будет выглядеть примерно так:

boost::optional<Item> pop();

Использование типов опций - лучший способ вернуть то, что может или не может быть доступно.

0 голосов
/ 03 мая 2010

Единственная причина, по которой я вижу использование этого синтаксиса в C ++:

void pop(Item& removed);

, если вы беспокоитесь о ненужных копиях.

если вы вернете Item, то может потребовать дополнительную копию объекта, которая может быть дорогой.

В действительности, компиляторы C ++ очень хорошо разбираются в копировании и почти всегда реализуют оптимизацию возвращаемого значения (часто даже когда вы компилируете с отключенной оптимизацией), что делает спор спорным и может даже означать простое «возвращение по значению» версия становится быстрее в некоторых случаях.

Но если у вас преждевременная оптимизация (если вы обеспокоены тем, что компилятор может не оптимизировать копию, даже если на практике это будет делать это), вы может приводить доводы в пользу «возврата» параметров путем присвоения ссылочного параметра.

Подробнее здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...