Consider something like this:
typedef std::unordered_multiset<int> Set;
typedef std::set<Set> SetOfSets;
SetOfSets somethingRecursive(SomeType somethingToAnalyze) {
Set s;
// ...
// check base cases, reduce somethingToAnalyze, fill in s
// ...
SetOfSets ss = somethingRecursive(somethingToAnalyze);
ss.insert(s);
return ss;
}
This approach is fairly standard for problems like generating subsets, permutations, etc. However, I tried making a diagram of what exactly Return Value Optimization should optimize here given the fairly complex internal data structure of the type (std::unordered_multiset
is a hash table and std::set
is 'typically' a binary search tree) and, well, I can only hope that compilers are smarter than me.
So, talking performance and (in case it matters) C++14
, can I return a SetOfSets
here or should I just pass it by reference as an out parameter?
Compilers often perform Named Return Value Optimization (NRVO) in such cases, but it is not guaranteed.
In the context of the C++ programming language, return value optimization (RVO) is a compiler optimization that involves eliminating the temporary object created to hold a function's return value. RVO is allowed to change the observable behaviour of the resulting program by the C++ standard.
> Note also that C doesn't have return-value-optimization, hence all your struct-returning functions will cause a call to memcpy (won't happen when compiled in C++ mode of course).
Before C++17, you cannot rely on copy elision at all, since it is optional. However, all mainstream compilers will very likely apply it (e.g., GCC applies it even with -O0
optimization flag, you need to explicitly disable copy elision by -fno-elide-constructors
if you want to).
However, std::set
supports move semantics, so even without NRVO, your code would be fine.
Note that in C++17, NRVO is optional as well. RVO is mandatory.
To be technically correct, IMO, there is no RVO in C++17, since when prvalue is returned, no temporary is materialized to be moved/copied from. The rules are kind of different, but the effect is more or less the same. Or, even stronger, since there is no need for copy/move constructor to return prvalue by value in C++17:
#include <atomic>
std::atomic<int> f() {
return std::atomic<int>{0};
}
int main() {
std::atomic<int> i = f();
}
In C++14, this code does not compile.
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