Closed Manu343726 closed 8 years ago
What its the runtime overhead of this Optional template compared to just returning a pointer that could be nullptr and checking it? Will be optimized by compiler in some cases?.
Also, why use the Optional this way, using a variant itself, instead of just doing an Optional without using the variant template.
What its the runtime overhead of this Optional template compared to just returning a pointer that could be nullptr and checking it? Will be optimized by compiler in some cases?.
First of all, a pointer means a cache-miss, the first thing you should avoid if performance is your concern these days. Also nullable objects are not an option since involve dynamic allocation (With all the overhead involved). Optional types provide a type-safe cache-friendly alternative for nullable types. Finally, optional values use value semantics as any good C++ does.
Also, why use the Optional this way, using a variant itself, instead of just doing an Optional without using the variant template.
Becuase the internals (aligned storage + flag) are exactly the same, so I tried to not bloat the library. Don't forget this is for learning purposes.
However, note even similar, these are not exactly the same abstractions. Variants (Sum types) are usually implemented with different flavors:
variant<Ts...>
an extra state "empty" is valid. This is the case of our cpp::Variant
for example. This has the advantage that you don't have to care about default-construction: What happens in a non-nullable variant at default construction? At least one of the Ts
should be default constructible (Else the variant cannot be defaut constructible), and if there are many of these, which one should be picked for default initialization of the variant?
Is this "nullable" flavor which provides the optional-like functionallity.v
of type T
: What happens if the move/copy constructor throws when assigning a new value? The assigned failed, but if you don't put special care the previous value of the variant is also lost. boost::variant
takes the "safe" approach and allocates an extra temporary buffer to backup the variant value prior to assignment. This way if something goes wrong you can roll back the operation. This behavior was rejected for the "Lenexa Variant", the variant being proposed for C++17 because of having too overhead.Check N4516 for an in-depth explanation of the variant design. I picked variant as an example since it's a real problem, currently a hot topic in the C++ community, and also a quite challenging feature to write.
Actually this variant can be improved a lot. For example, currently visitation has O(n)
complexity, but since types are known at compile time you can write a constexpr
lookup table to do visitation. But variant already involved a lot of templates, so adding also constexpr
to the mix... I'm doing this to teach people, not to make them cry and run away
Maybe directly wrapping a variant? An unary variant with empty state can be considered an optional