0

假设我有以下 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++ 新手,对编译器了解不多,但我会假设通过一些编译器魔法,我的原始函数不会贵得多。(而且我会避免自己初始化集合。)我错了吗?关于指针和返回复制我应该知道些什么才能理解这一点?

4

2 回答 2

3

不,这通常根本没有优势。如今,几乎所有合理的编译器都将利用命名返回值优化(参见此处)。这有效地消除了前一个示例中的任何性能损失。

如果你真的想深入了解细节,请阅读Dave Abrahams 的这篇文章(boost 的主要贡献者之一)。然而,长话短说,只需返回值。它可能更快。

于 2013-04-15T04:39:59.050 回答
0

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

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

我会这样做

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);
                  ^^ 
于 2013-04-15T04:36:54.060 回答