Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overhead of std::optional<T>?

Now that std::experimental::optional has been accepted (or is about to be accepted), I wonder what is the overhead and the consequences on the assembly generated when the inner value is get by the following operators :

->
*
value
value_or

compared to the case without std::optional. It could be particularly important for computationaly intensive programs.

For example, what would be order of magnitude of the overhead on operations on a std::vector<std::experimental::optional<double>> compared to a std::vector<double> ?

like image 335
Vincent Avatar asked May 07 '14 16:05

Vincent


2 Answers

Besides the other answer, you should also consider that std::optional requires additional memory.

Often it's not just an extra byte, but (at least for "small" types) a 2x space overhead due to padding .

Maybe RAM isn't a problem but that also means fewer values available in the cache.

A sentinel value, if specific knowledge allows to use it, could be a better choice (probably in the form of markable to keep type safety).

An interesting reading is: Boost optional - Performance considerations

like image 93
manlio Avatar answered Oct 19 '22 10:10

manlio


-> and * ought to have zero overhead.
value and value_or ought to have the overhead of one branch: if(active)
Also, copy/move constructor, copy/move assignment, swap, emplace, operator==, operator<, and the destructor ought to also have the overhead of one branch.
However, one banch of overhead is so small it probably can't even be measured. Seriously, write pretty code, and don't worry about the performance here. Odds are making the code pretty will result in it running faster than if you tried to make it fast. Counter-intuitive, but do it anyway.

There are definitely cases where the overhead becomes noticible, for instance sorting a large number of optionals. In these cases, there's four situations,
(A) all the optionals known to be empty ahead of time, in which case, why sort?
(B) Some optionals may or may not be active, in which case the overhead is required and there is no better way.
(C) All optionals are known to have values ahead of time and you don't need the sorted-data in place, in which case, use the zero overhead operators to make a copy of the data where the copy is using the raw type instead of optional, and sort that.
(D) All optionals are known to have values ahead of time, but you need the sorted data in-place. In this case, optional is adding unnecessary overhead, and the easiest way to work around it is to do step C, and then use the no-overhead operators to move the data back.

like image 15
Mooing Duck Avatar answered Oct 19 '22 10:10

Mooing Duck