【发布时间】:2018-01-29 12:39:20
【问题描述】:
考虑这样的事情:
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;
}
这种方法对于生成子集、排列等问题是相当标准的。但是,鉴于该类型的内部数据结构相当复杂(std::unordered_multiset 是哈希表和std::set'通常'是二叉搜索树),我只能希望编译器比我更聪明。
那么,谈论性能和(以防万一)C++14,我可以在这里返回SetOfSets,还是应该通过引用将其作为输出参数传递?
【问题讨论】:
-
您使用的不是 RVO,而是 NRVO。区别是微妙的,但它就在那里 :) 人们经常把后者放在前者之下,所以是的。
-
@Rakete1111 NRVO 是 RVO 的一个子集。它有一个特殊的名称,主要是因为各种编译器首先为右值实现了 RVO,然后在 2003 年左右添加 NRVO 是一件大事。
-
我需要查看 C++17 要求以获得完整答案。但是经典的 NRVO 并不关心类型有多“复杂”。一个典型的编译器基本上只是计算“唯一的返回语句是
return ss;和ss是一个本地非静态类类型变量,所以我不会将ss放在我自己的堆栈空间中,而是使用返回地址由调用者首先为其提供。” -
@sigil:绝对不是。在 C++17 之前不能保证优化。虽然您可以通过使用调试器单步执行程序或将特殊消息放入构造函数来查看特定编译器正在执行的操作。
-
@YSC 因为从技术上讲,它不是复制省略。在 C++17 中,当返回纯右值时,没有临时物化。只是效果是“例如,或多或少地应用了 RVO”。请注意,这会产生后果 - 即使不存在复制或移动构造函数,您也可以在 C++17 中返回纯右值 (
std::atomic)。