std::optional - construct empty with {} or std::nullopt?
In this case, {}
invokes value-initialization. If optional
's default constructor is not user-provided (where "not user-provided" means roughly "is implicitly declared or explicitly defaulted within the class definition"), that incurs zero-initialization of the entire object.
Whether it does so depends on the implementation details of that particular std::optional
implementation. It looks like libstdc++'s optional
's default constructor is not user-provided, but libc++'s is.
When explicitly initializing std::optional's, should I use nullopt?
They both have the same effect - I would prefer the simplest form (KISS), but it is subjective, pick one and be consistent. You may also wish to be consistent with how you treat other objects in your code, do you normally rely on default initialization (e.g. int i{}
vs int i{0}
)?
Personally when I see redundant code, like initalizing an object to its default value explicitly, it does reduce my confidence in the author by a slight margin - does the author really understand what he is doing and trying to be extra safe / explicit / readable, or was he simply too lazy to read the documentation? It makes me wonder, does the author understand what happens when he writes std::vector<std::optional> v(n)
, or more complex examples? If this is a documented decision, in a coding style, then all is fine, I can understand the need to improve readability.
Why do we need std::nullopt
No.
This is a perfectly valid way to default-construct an optional
.
Even for assignment, you can copy-assign a default-constructed optional
with = {}
instead of using std::nullopt
:
cppreference actually says as much:
The constraints on
nullopt_t
's constructors exist to support bothop = {};
andop = nullopt;
as the syntax for disengaging an optional object.
… as does the original proposal for the feature:
Note that it is not the only way to disengage an optional object. You can also use:
op = std::nullopt;
You might ask yourself why, then, std::nullopt
exists at all. The proposal addresses this, too:
it introduces redundancy into the interface
[similar example]
On the other hand, there are usages where the usage of nullopt cannot be replaced with any other convenient notation:
void run(complex<double> v);
void run(optional<string> v);
run(nullopt); // pick the second overload
run({}); // ambiguous
if (opt1 == nullopt) ... // fine
if (opt2 == {}) ... // illegal
bool is_engaged( optional<int> o)
{
return bool(o); // ok, but unclear
return o != nullopt; // familiar
}While some situations would work with {} syntax, using nullopt makes the programmer's intention more clear. Compare these:
optional<vector<int>> get1() {
return {};
}
optional<vector<int>> get2() {
return nullopt;
}
optional<vector<int>> get3() {
return optional<vector<int>>{};
}
In short, std::nullopt
can be useful, but in your case it simply comes down to style.
What are the advantages/disadvantages of std::optional over nullptr?
The sole job of std::optional
is to extend the type domain by an additional "null" value. Every pointer type T*
already has a value considered "null" - nulltpr
.
Thus, it's not a good idea to compare those two directly, because they answer different questions. Sometimes it's important to differentiate between "no result" and "null result"1 (which is one of the possible interpretations), sometimes it's not. You should use whichever fits your needs.
Now if the only reason the code returned a pointer was to make use of the implicit pointer nullability, then the proper solution would be to change it to return std::optional<SomePointer>
(or perhaps std::optional<std::reference_wrapper<SomePointer>>
) instead, but that's not what you asked about.
1 Of course at this point it's also worthwhile to consider something like e.g. struct NoResult {}; using Result = std::variant<NoResult, SomePointer*>;
to make it even more explicit.
How to assign nothing to std::optionalT?
I wouldn't say there is one "standard" way to assign nothing to std::optional.
If you read the proposal for std::optional
("A proposal to add a utility class to represent optional objects") the authors present two ways, in this order:
We put the extra requirements in the standardese to make sure that the following syntax works for resetting the optional:
op = {};
We consider that this will become a common idiom for resetting (putting into default-constructed state) values in C++
Note that it is not the only way to disengage an optional object. You can also use:
op = std::nullopt;
std::optional::reset
did not exist at the time of writing that proposal, so it was not mentioned, however it is also a valid way to do it.
How do I obtain a non-empty optional with the value inside it being default constructed?
The easiest way is
std::optional<std::vector<int>> ov = {{}};
alternatives include
std::optional<std::vector<int>> ov(std::in_place);
sadly there is no way to do this with assignment instead of construction; {{}}
is ambiguous, and the std::in_place
constructor is explicit.
There you have to call ov.emplace()
.
You could create a helper object;
struct non_empty {
template<class T>
constexpr operator std::optional<T>()const{ return {{}}; }
};
then
ov = non_empty{};
does the job.
Related Topics
Advantages of Using Initializer List
Constexpr Not Working If the Function Is Declared Inside Class Scope
What Is the Purpose of Max_Digits10 and How Is It Different from Digits10
System() Calls in C++ and Their Roles in Programming
How Is Floating Point Conversion Actually Done in C++(Double to Float or Float to Double)
How to Output Array of Doubles to Hard Drive
What Is the Practical Use of Pointers to Member Functions
Explicit Call to Destructor Is Not Destroying My Object Why
"Volatile" Qualifier and Compiler Reorderings
Opencv Cv::Mat to Std::Ifstream for Base64 Encoding
Threadsafe Vector Class for C++
Boost::Spirit How to Parse and Call C++ Function-Like Expressions
What Does the & (Ampersand) at the End of Member Function Signature Mean
Fine Tuning Hough Line Function Parameters Opencv
What Is the Meaning of 'Struct X Typedef' VS. 'Typedef Struct X'