Say I have an RAII class, instances of which should never be copied:
class Session {
public:
Session(); // Allocates a resource and sets generates a unique Session::id.
~Session(); // Frees the resource
Session(const Session&) = delete;
Session& operator = (Session&) = delete;
private:
std::uint32_t id;
}
Given that I can't allow copies, I'd like to allow moving, so I need to implement the move constructor and move-assignment operator but I'm not sure what I should do with Session::id
of the moved instance.
I can either:
-1
as the invalid value)std::optional
and set it to std::nullopt
to invalidate it.Which (if either) of those options is correct?
Since this can be done without std::optional
by just sacrificing one value out of the 232 possible id
s, I'd do like std::string::npos
and initialize a constant of the unsigned type your id
has with -1
.
Example:
class Session {
public:
// the constant used to signal an invalid id:
static constexpr std::uint32_t invalid_id = static_cast<std::uint32_t>(-1);
Session() :
id(id_counter++)
/* allocate the resource */
{}
Session(const Session&) = delete;
Session(Session&& other) noexcept :
id(std::exchange(other.id, invalid_id)) // exchange with the invalid id
/* move or exchange the resource */
{}
Session& operator=(const Session&) = delete;
Session& operator=(Session&& other) noexcept {
// check for self-assignment if needed
std::swap(id, other.id);
// swap the resource
return *this;
}
~Session() {
if(id != invalid_id) { // if the check is even needed
/* free the resource */
}
}
private:
inline static std::uint32_t id_counter = 0;
std::uint32_t id;
};
An option would be to let 0
be the invalid_id
if that would feel more natural in your case. You'd just have to initialize invalid_id
with 0
and change the id counting to id(++id_counter)
.