I know that std::optional<T&> isn't supported in the standard. This question is about whether passing std::optional<T>& has any performance advantage
Sample code (https://godbolt.org/z/h56Pj6d6z) reproduced here
#include <ctime>
#include <iomanip>
#include <iostream>
#include <optional>
void DoStuff(std::optional<std::string> str) {
if (str) std::cout << "cop: " << *str << std::endl;
}
void DoStuffRef(const std::optional<std::string>& str) {
if (str) std::cout << "ref: " << *str << std::endl;
}
int main() {
std::optional<std::string> str = {};
DoStuff(str);
DoStuffRef(str);
str = "0123456789012345678901234567890123456789";
DoStuff(str);
DoStuffRef(str);
}
(My actual use case is an optional for a complex user-defined type, but I hope that a long string would do the same compiler-wise)
In this case, does DoStuffRef actually save any copying effort compared to DoStuff?
I tried to look at godbolt output but I don't know enough assembly to be sure. I do see that in the case of DoStuff, there seems to be a temp std::optional<T> created which is not present in DoStuffRef so my suspicion is that yes, passing an optional by reference save some copying
Appreciate the help!
If you pass actual std::optional<std::string> then yes, there would be no copy. But if you pass just std::string then temporary optional has to be constructed first, resulting in a copy of the string.
Passing std::optional<std::string> by value as in DoStuff will be slower any way since the std::optional<> represents the object and according to definition
Any instance of optional<T> at any given point in time either contains a value or
does not contain a value.
If an optional<T> contains a value, the value is guaranteed to be allocated as part
of the optional object footprint
The key here is the optional object footprint term
Let's say an emtpy std::string occupies 16 bytes - then optional for empty string will take at least 16 bytes. And passing optional by value will lead to 16 bytes copy all the time (excluding use case when compiler can pass it as rvalue & apply move semantic to entire optional object instance)
Take a look at representative benchmark for the provided use case:
std::optional<std::string> str = {};
DoStuff(str); // pass optional<> without value
DoStuffRef(str); // still 2 times faster than above call
std::optional<std::string> str = {""};
DoStuff(str); // pass optional<> with value - empty string
DoStuffRef(str); // still 7 times faster than above call
str = "0123456789012345678901234567890123456789";
DoStuff(str); // pass optional<> with big string
DoStuffRef(str); // 60X times faster than above call

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With