在函数中返回大对象

2023-12-05

比较以下两段代码,第一段使用对大对象的引用,第二段将大对象作为返回值。对“大对象”的强调是指,不必要地重复对象的副本会浪费周期。

使用对大对象的引用:

void getObjData( LargeObj& a )
{
  a.reset() ;
  a.fillWithData() ;
}

int main()
{
  LargeObj a ;
  getObjData( a ) ;
}

使用大对象作为返回值:

LargeObj getObjData()
{
  LargeObj a ;
  a.fillWithData() ;
  return a ;
}

int main()
{
  LargeObj a = getObjData() ;
}

第一个代码片段不需要复制大对象。

在第二个片段中,对象是在函数内部创建的,因此通常在返回对象时需要一个副本。然而,在这种情况下,在main()正在声明该对象。编译器会先创建一个默认构造的对象,然后复制由getObjData(),或者它会像第一个片段一样有效吗?

我认为第二个片段更容易阅读,但恐怕效率较低。

Edit:通常,我会考虑案例LargeObj是通用容器类,出于论证的目的,其中包含数千个对象。例如,

typedef std::vector<HugeObj> LargeObj ;

所以直接修改/添加方法LargeObj不是一个可以直接访问的解决方案。


第二种方法更加惯用,也更具表现力。阅读代码时可以清楚地看出,该函数对参数没有先决条件(它没有参数),并且它实际上会在内部创建一个对象。对于普通读者来说,第一种方法不太清楚。该调用意味着该对象将被更改(通过引用传递),但不清楚传递的对象是否有任何先决条件。

关于副本。您发布的代码没有使用赋值运算符,而是使用复制构造。 C++ 定义了返回值优化所有主要编译器都实现了这一点。如果您不确定可以在编译器中运行以下代码片段:

#include <iostream>
class X
{
public:
    X() { std::cout << "X::X()" << std::endl; }
    X( X const & ) { std::cout << "X::X( X const & )" << std::endl; }
    X& operator=( X const & ) { std::cout << "X::operator=(X const &)" << std::endl; }
};
X f() {
    X tmp;
    return tmp;
}
int main() {
    X x = f();
}

使用 g++ 你会得到一行X::X()。编译器在堆栈中保留空间x对象,然后调用构造函数tmp over x(实际上tmp is x。里面的操作f()直接应用于x,相当于您的第一个代码片段(通过引用传递)。

如果您没有使用复制构造函数(您是否编写过:XX; x = f();)然后它会创建两个x and tmp并应用赋值运算符,产生三行输出:X::X() / X::X() / X::运算符=。因此,在某些情况下,效率可能会稍低一些。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在函数中返回大对象 的相关文章

随机推荐