如何最小化列表构造函数(复制构造函数)的调用次数?

时间:2012-11-01 10:39:16

标签: c++

我有以下比较方法。 方法比较并返回diff结果。

我希望最小化结果列表被复制的次数(时间和分配)。

这样做的一种方法是为结果添加额外的引用参数,但我喜欢utils函数是关闭的(它们不会改变值),所以我宁愿避免这种情况。

使用const& amp;可以避免一个副本。在作业中

const& list<uint32> diff = getDiffNewElements (...)

,可以通过一种方法避免本地复制到临时吗?

diff方法:

list<uint32> getDiffNewElements(const list<Row>& src ,const list<Row>& dst) {
    list<uint32> result;

        ... Do Some compare

        return result;
}

2 个答案:

答案 0 :(得分:2)

您提供的代码中可能有两个副本。函数内部的一个,从变量result到返回的对象。如果功能的复杂性允许,NRVO将负责这一点。如果看起来有一个return语句,那么编译器将忽略该副本(假设您没有使用编译器标志禁用它并且您已启用某些优化级别)。

第二个潜在副本位于调用者中,从返回值到最终存储。编译器几乎总是忽略该副本,并且在此处比在NRVO情况下更简单:调用约定(我知道的所有调用约定)确定调用者为返回的对象保留空间,并且它将指向该位置的隐藏指针传递给该函数。该函数依次使用该指针作为第一个副本的目标。

函数T f()转换为void f( uninitialized<T>* __ret )(没有uninitialized<>这样的东西,但是请耐心等待)并且函数的实现在复制时使用该指针作为目标在return声明中。在调用者站点上,如果您有T a = f();,编译器会将其转换为T a/*no construction here*/; f(&a);

问题中有一些有趣的代码似乎表明你过去曾误导过:const list<uint32>& diff = getDiffNewElements(...)。使用引用而不是直接存储值(如在list<uint32> diff = getDiffNewElements(...)中)对所创建的副本数量没有任何影响。 getDiffNewElements仍然需要复制(或删除副本)到返回的对象,并且该对象位于调用者的范围内。通过获取const引用,您告诉编译器您不想直接命名该对象,而是将其保留为范围中的未命名对象,并且您只想使用对它的引用。从语义上讲,它可以转化为:

T __unnamed = getDiffNewElements(...);  // this copy can be elided
T const& diff = __unnamed;

编译器是免费的,并且可能会使用标识符diff作为__unnamed的别名来优化引用,而不需要额外的空间,因此通常它不会比替代方案更糟糕,但代码稍微复杂一点,没有任何优势。

很久以前,当我有时间的时候,我开始写博客,写了几篇关于价值语义的文章,(N)RVO和复制文章。你可能想看看。

答案 1 :(得分:0)

你正朝着错误的方向前进。您的getDiffNewElements方法不会创建不必要的副本,因为现代编译器会RVO(注释中指出了这一点,但如果您的编译器没有执行RVO,那么您无能为力, const&无济于事。优化此函数的方法是返回vector而不是list,因为您可以在reserve上调用vector并在每次push_back时避免内存分配一个新元素。 list没有使用默认分配器预分配内存,并且没有reserve方法来执行此操作。