Reputation: 5570
I need to implement a quick solution for optional values. I don't want to drag in any third party libraries.
How are the optional classes implemented in general? Does an optional object still default-construct the underlying object when it's in the 'null-state'?
Upvotes: 18
Views: 21695
Reputation: 1536
std::optional from Scratch introduces how to implement a optional class
Upvotes: 4
Reputation: 10896
Here is a start to mimicking std::optional. Not the trickiest implementation and has a lot more that should be added.
template <typename T>
struct optional {
private:
bool _has_value;
T _value;
public:
optional() : _has_value{false}, _value{} {}
optional(T v) : _has_value{true}, _value{v} {}
bool has_value() const {return _has_value;}
T value() const {
if (_has_value) return _value;
throw std::bad_optional_access();
}
T value_or(T def) const {
return _has_value ? _value : def;
}
optional<T>& operator=(T v) {
_has_value = true;
_value = v;
return *this;
}
void reset() {_has_value = false;}
};
Upvotes: -1
Reputation: 38919
In c++14 or earlier you can use a null-checked T*
or just a std::pair<T, bool>
. The problem with the latter is if your default construction of T
is expensive, that may be wasteful.
In c++17 or later you can still use T*
but you can also use std::optional<T>
. Here the latter only constructs a T
if it is valid.
It's noteworthy that the std::optional
is a good option in only a few cases: https://topanswers.xyz/cplusplus?q=923#a1085
Upvotes: 3
Reputation: 254441
How are the optional classes implemented in general?
Typically, a boolean flag to indicate whether or not it's empty, and a suitably sized and aligned byte array to store the value.
Does an optional object still default-construct the underlying object when it's in the 'null-state'?
No; that would impose an unnecessary requirement on the stored type, as well as causing potential unwanted side-effects. The stored object would be created with placement-new when the optional
becomes non-empty, and destroyed with a destructor call when it becomes empty.
For a quick-and-dirty implementation, if you don't need all the flexibility of the Boost or proposed standard versions, you could simply store a default-constructed object.
I don't want to drag in any third party libraries.
I would reconsider why you don't feel you want that. The Boost implementation is header-only, well tested, and should be directly replaceable by the standard version if and when that arrives. I'd certainly trust it more than something I cobbled together myself.
Upvotes: 16
Reputation: 1421
First of all I highly recommend you to take a look at Boost (specifically at Boost.Optional) - it is almost standard practice to use Boost and it would save you reinventing the wheel.
If for some reason you are reluctant to use Boost.Optional, there are a bunch of similar header-only libraries, for example https://github.com/akrzemi1/Optional
Upvotes: 3