Хотя кратковременное решение - возвращать значение, лучше, если pop()
имеет тип void
.
template <typename T>
void Stack<T>::pop() {
...
}
Причина в том, что вы не можете написать исключительную pop()
-функцию, которая возвращает что-то:
template <typename T>
T Stack<T>::pop() {
T foo = stor_.top(); // May throw.
stor_.pop(); // This line shall never throw.
return foo; // May throw.
}
Вторая строка (с pop()
) никогда не должна бросать что-либо, потому что деструкторы не должны бросать . Поэтому разумно предположить, что строка не является высокой и всегда будет успешной (кроме случаев, когда вы выдвигаете пустой контейнер).
Первая и третья строка могут быть сброшены, потому что данные копируются.
Теперь представьте, что
T foo = stor_.top(); // May throw.
stor_.pop(); // This line shall never throw.
работает безупречно: у вас есть готовое к возвращению значение, и вы успешно изменили состояние удерживающего объекта.
Но тогда
return foo; // May throw.
Взрыв Это исключение. Что случилось:
- Функция не удалась, абонент не получил ничего, кроме исключения
- Тем не менее, состояние объекта было изменено.
- И никто больше не имеет обновленной копии утерянного объекта, которая обычно содержит важные деловые данные, которые босс позвонил несколько секунд назад, прежде чем произошел несчастный случай со смертельным исходом
Это противоречит Гарантии Авраама :
Гарантия отсутствия бросков: операция не вызовет исключение.
Сильная гарантия: что операция либо успешно завершена, либо вызвала исключение, оставляя состояние программы в точности таким, каким оно было до начала операции.
Основная гарантия: что инварианты компонента сохранены, а ресурсы не просочились. Часто упоминается как слабая гарантия, поскольку после исключения система остается в безопасном, но неизвестном состоянии.
И с pop()
, который возвращает значение, вы не можете гарантировать, что никакая информация не будет потеряна.
См. Также ПОЛУЧИЛ # 8 и ПОЛУЧИЛИ # 82