patterncppMinor
Reinventing std::optional
Viewed 0 times
reinventingstdoptional
Problem
I decided to make my own version of C++17's std::optional
It's basically a class that can optionally hold a variable (as the name suggests), it avoids having to resort to
I'd like some feedback regarding the overall implementation
It's basically a class that can optionally hold a variable (as the name suggests), it avoids having to resort to
std::pair to check whether a variable is set.I'd like some feedback regarding the overall implementation
template
class Optional {
public:
/**
* The constructor
*/
Optional() :
is_set_(false) {}
/**
* The constructor
* @param val The value to set it to
*/
Optional(const T& val) :
val_(val), is_set_(true) {}
/**
* Sets the value
* @param val The value to set it to
*/
void set(const T& val) { val_ = val; is_set_ = true; }
/**
* @return The value
*/
T get() const { return val_; }
/**
* Clears the value
*/
void clear() { val_ = T{}; is_set_ = false; }
/**
* @return Whether the value is set
*/
bool empty() { return !is_set_; }
/* Operators */
Optional operator=(const T& val) {
val_ = val;
is_set_ = true;
return *this;
}
operator T() const {
return val_;
}
bool operator==(const bool& val) const {
return (is_set_ == val);
}
explicit operator bool() const { return is_set_; }
private:
T val_{};
bool is_set_ = false;
};Solution
Prefer value type semantic
Try to make classes default constructible and equality comparable whenever this makes sense. Currently your
Even though it might make sense to have an optional. Also consider this example
Here is an example of how to use
Do not return by value if you can
The line
Makes a copy of
instead.
Make use of move assignments
Currently you have to copy values into your optional. But what, if you just want to move something big that you want to return from a function? You
need to add constructors for rvalue-
Try to make classes default constructible and equality comparable whenever this makes sense. Currently your
Optional class doesn't fulfil neither. The following code will not compileclass A { int a; A() = delete; };
int main()
{
Optional i;
}Even though it might make sense to have an optional. Also consider this example
struct B { B() { /* insert something super long */ } }:
int main()
{
Optional opt_b; // this line takes really long!
}Here is an example of how to use
std::aligned_storage to use uninitialised memory. I think this could help you as well.Do not return by value if you can
The line
T get() const { return val_; }Makes a copy of
T while returning val_. Imagine val_ is a very big std::string. This could be very expensive in code which calls get() multiple times. If you want read-only access, prefer to useconst T& get() const& noexcept { return val_; }instead.
Make use of move assignments
Currently you have to copy values into your optional. But what, if you just want to move something big that you want to return from a function? You
need to add constructors for rvalue-
Ts.Optional(T&& value)
: val_{std::move(value)}
, is_set_{true} {}Code Snippets
class A { int a; A() = delete; };
int main()
{
Optional<A> i;
}struct B { B() { /* insert something super long */ } }:
int main()
{
Optional<B> opt_b; // this line takes really long!
}T get() const { return val_; }const T& get() const& noexcept { return val_; }Optional(T&& value)
: val_{std::move(value)}
, is_set_{true} {}Context
StackExchange Code Review Q#158311, answer score: 6
Revisions (0)
No revisions yet.