У меня есть игра с не копируемыми Item
с, поскольку они должны быть уникальными:
class Item {
Item() noexcept;
Item(Item&&) noexcept;
Item(Item const&) = delete;
// ...
};
class Creature
способен получить Item
и добавить его к своим inventory
:
void Creature::receive_item(Item&& item) noexcept {
this->inventory.push_back(std::move(item));
}
void caller_code() {
Creature creature;
Item item;
// ...
creature.receive_item(std::move(item));
}
Этот подход кажется красивым и чистым, но есть небольшая проблема: если какая-то часть моего кода может восстановиться после std::bad_alloc
и, следовательно, перехватывает одну из recieve_item()
* push_back()
, логика c в игре не определена: Item
был перемещен в функцию, которая не смогла сохранить одну, поэтому она просто потерялась. Более того, спецификатор noexcept
должен быть удален только для этой возможности.
Таким образом, я могу обеспечить безопасность исключений таким образом (укажите, если я ошибаюсь):
void Creature::receive_item(Item& item) {
this->inventory.resize(this->inventory.size() + 1);
// if it needs to allocate and fails, throws leaving the item untouched
this->inventory.back() = std::move(item);
}
void caller_code() {
Creature creature;
Item item;
// ...
creature.receive_item(item); // no moving
}
Однако теперь у нас появились новые недостатки:
- отсутствие
std::move()
в коде вызывающего абонента скрывает факт перемещения item
; - в размер изменения (+ 1) «часть просто безобразна и может быть неправильно понята при просмотре кода.
Вопрос в названии. Является ли безопасность исключений даже для такого странного случая хорошей конструкцией?