In one of the previous articles, we’ve looked at std::optional and how sentinels can be used as alternatives.
Unfortunately, most people are looking for a “silver bullet” universally true rules that can be applied without any considerations. Well, there are no such rules in performance and as an example, let me use a true story. During code review of the function that had an optional string as one of the parameters
one of the code reviewers requested to remove optional referencing one of my older comments mentioning overhead associated with std::optional.
I replied explaining that in this particular case using optional is both better API and may even be faster, so there is really no reason to get rid of it. How can it be faster? Well, “creating” std::nullopt is certainly cheaper than creating an empty string and creating a non-empty string should be only marginally faster than creating an optional with the same string.
To back my statement I’ve shared benchmark results that indicate that creating an empty string is 16X slower than using std::nullopt and creating an optional with non-empty string is only 1.1 slower than creating the same string directly.
The moral of the story is that every performance decision should be considered in proper context. In this particular case, using std::optional is not only better API, as it explicitly communicates optionality, but also comes with very favorable performance trade-off, since in production, majority of usages end up with this parameter missing.
good one!