...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
In C++ you can create an automatic object of a scalar type, and manipulate it, without assigning it the initial value.
{ int i; // indeterminate value populate(&i); cout << i; }
Such an object is said to have indeterminate value.
If you subsequently assign a proper value to the object, all is fine; but
if the program tries to read an indeterminate value, this is undefined
behavior', and since C++26 this is erroneous behavior.
In any case, the program is now likely to do something else than what the
programmer intended. In case you have some object i
,
and you do not know if it has an indeterminate value, or a normal, intended,
value, there is no way to check it, because the checking would require reading
the value.
This is one of the primary problems that optional
was intended to address: so that you may have a type that knows whether it
has been assigned a proper value, and it can tell you that if requested.
In the case of type int
the
internal representation of such a class could be:
class OptionalInt { bool _has_value = false; int _value; };
In the general case, the internal representation is something equivalent to:
template <typename T> class Optional { bool _has_value = false; alignas(T) char _value [sizeof(T)]; };
Next, because we need to pass around these "optional" int
s as normal int
s,
like returning them from functions, when copying, we need to copy _has_value
, which indicates whether we
have the value or not, and, if we do have value, and only then, to also copy
_value
.
This means that our type requires deep copy semantics.