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?
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.