I have a game with non-copyable Items 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?