Reputation: 820
I would like to ask how to return an std::optional
in an efficient way and I would like to use std::make_optional()
.
For example lets have this code snippet:
std::optional<Path> CreateCanonicalPath(const std::string_view& path)
{
std::error_code errorCode;
const auto result = std::filesystem::weakly_canonical(std::filesystem::u8path(path), errorCode);
return !errorCode ? std::make_optional(result) : std::nullopt;
}
I am particularly interested whether there is any optimization in passing result
to std::make_optional
. Would it be better to use std::make_optional(std::move(result))
?
And does it prevent any RVO or NVRO?
The result
is a local variable but it is not exactly in a return statement so I assume the compiler can't use move by itself.
Upvotes: 14
Views: 9311
Reputation: 118310
There's one obvious improvement:
std::optional<Path> CreateCanonicalPath(const std::string_view& path)
{
std::error_code errorCode;
auto result = std::filesystem::weakly_canonical(std::filesystem::u8path(path), errorCode);
return !errorCode ? std::make_optional(std::move(result)) : std::nullopt;
}
Making the transitory object const
will require employing copy-construction as part of instantiating the returned std::optional
. This tweak should result in employing move semantics.
After this point, any further improvements would dependent highly on the compiler behavior. It's unlikely, but it's possible that, if benchmarked, some minor performance variances can be observed with alternate syntaxes, such as, for example:
std::optional<Path> CreateCanonicalPath(const std::string_view& path)
{
std::error_code errorCode;
auto result = std::make_optional(std::filesystem::weakly_canonical(std::filesystem::u8path(path), errorCode));
if (errorCode)
result.reset();
return result;
}
If it's determined that the compiler will choose to elide the copy, as allowed by NVRO, then it's worth benchmarking this, as well. But only actual benchmarking will produce useful results.
Upvotes: 16