c – 对于复杂的返回类型,我可以依赖命名返回值优化吗?

考虑这样的事情:

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,还是应该通过引用作为out参数传递它?

最佳答案
在C 17之前,你根本不能依赖复制省略,因为它是可选的.但是,所有主流编译器都很可能会应用它(例如,即使使用-O0优化标志,GCC也会应用它,如果需要,您需要通过-fno-elide-constructors明确禁用复制省略).

但是,std :: set支持移动语义,所以即使没有NRVO,你的代码也没问题.

请注意,在C 17中,NRVO也是可选的. RVO是强制性的.

为了在技术上正确,IMO,C 17中没有RVO,因为当返回prvalue时,没有临时实现移动/复制.规则有点不同,但效果或多或少相同.或者,甚至更强,因为在C 17中不需要复制/移动构造函数来按值返回prvalue:

#include <atomic>

std::atomic<int> f() {
  return std::atomic<int>{0};
}

int main() {
  std::atomic<int> i = f();
}

在C 14中,此代码无法编译.

转载注明原文:c – 对于复杂的返回类型,我可以依赖命名返回值优化吗? - 代码日志