I have a game with non-copyable Item
s as they are supposed to be unique:
class Item {
Item() noexcept;
Item(Item&&) noexcept;
Item(Item const&) = delete;
// ...
};
class Creature
is capable of receiving an Item
and adding it to their 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));
}
This approach seems nice and clean but there's a small problem: if any part of my code can recover after std::bad_alloc
and therefore catches one thrown by recieve_item()
's push_back()
, the in-game logic is undefined: an Item
was moved to a function which failed storing one so it is just lost. Moreover, the noexcept
specifier has to be removed just for this possibility.
So, I can provide exception safety this way (please point it out if I'm wrong):
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
}
However, now we have new disadvantages:
- the lack of
std::move()
in the caller's code obscures the fact of moving theitem
; - the "resize(+1)" part is just ugly and may be misunderstood during a code review.
The question is in the title. Is exception safety even for such a weird case considered a good design?