函数接受一个指向集合的指针的优点,以避免在返回时复制

Advantage of function taking a pointer to a collection, to avoid copying on return?

本文关键字:复制 返回 指针 函数 一个 集合      更新时间:2023-10-16

假设我有以下c++函数:

// Returns a set containing {1!, 2!, ..., n!}.
set<int> GetFactorials(int n) {
  set<int> ret;
  int curr = 1;
  for (int i = 1; i < n; i++) {
    curr *= i;
    ret.insert(curr);
  }
  return ret;
}
set<int> fs = GetFactorials(5);

(这只是一个假的例子。关键是函数自己创建集合并返回它。)

我的一个朋友告诉我,与其按照我的方式编写函数,不如让函数接受一个指向集合的指针,以避免在返回时复制集合。我猜他的意思是:

void GetFactorials2(int n, set<int>* fs) {
  int curr = 1;
  for (int i = 1; i < n; i++) {
    curr *= i;
    fs->insert(curr);
  }
}
set<int> fs;
GetFactorials2(5, &fs);
我的问题是:第二种方法真的有很大的优势吗?我觉得很奇怪。我是c++新手,对编译器了解不多,但我认为通过一些编译器的魔法,我的原始函数不会那么昂贵。(这样我就不用自己初始化集合了。)我错了吗?关于指针和返回时复制,我应该知道些什么才能理解这个?

不,这通常是不有利的。如今,几乎所有合理的编译器都会利用命名返回值优化(见这里)。这有效地消除了前一个示例的任何性能损失。

如果您真的想了解细节,请阅读Dave Abrahams (boost的主要贡献者之一)的这篇文章。长话短说,但是,只是返回值。这样可能更快。

是的,它可能很昂贵。尤其是当布景变大的时候。这里没有理由不使用指针或引用。它将为您节省很多,并且您不会在可读性方面牺牲太多。

当你可以自己优化时,为什么要依赖编译器优化呢?编译器知道你的代码,但并不总是理解你的算法。

我会这样做

void GetFactorials2(int n, set<int>& fs) {
//                                   ^^
  int curr = 1;
  for (int i = 1; i < n; i++) {
    curr *= i;
    fs->insert(curr);
  }
}

,通话将保持正常。

set<int> fs;
GetFactorials2(5, fs);
                  ^^