2

当我们在函数中使用 return 语句返回用户定义的类型(特别是类)时会发生什么。假设我们有一个名为“DMatrix”的 c++ 类

DMatrix someFunc()
{  
  DMatrix mymat;
  /* Some operations on this matrix */  
  return mymat;  
};

在 main() 的某个地方,我想做:

DMatrix d;
d = someFunc();

在堆栈操作方面究竟调用了什么?
我想为了类 DMatrix 是可返回的,有一个复制构造函数(这样这个类的实例可以通过引用传递)和定义的 = 运算符就足够了。我对吗?

背后的动机:这个问题背后的动机是双重的。1)我使用一个定义了矩阵类型的库,比如说 DMatrix。我可以编写返回 DMatrix 类型的函数吗?
2)第二个原因当然是要更深入地了解返回自定义数据类型和返回 int 或 double 等基本数据类型在堆栈级别的区别。因此,在 C++ 中编写更好的类。也许这必须成为一个单独的问题。

4

2 回答 2

1

您应该实现一个复制构造函数,但请注意,这实际上是那些有趣的场景之一,您可能会看到二进制的“调试”版本和“发布”版本之间的语义差异。大多数编译器将优化对复制构造函数的调用并在此实例中执行返回值优化。在这种情况下,规范特别允许编译器使用复制构造函数来执行此操作。

尝试在复制构造函数中打印某些内容,您会发现在运行发布版本时不会打印,但在调试版本中会打印。

此外,如果您使用的是 C++11,则在您返回 mymat 时,mymat 将是所谓的右值(临时对象)。在 C++11 中可以声明一个移动构造函数以及一个复制构造函数,它将显式地将您的对象移动到外部范围而不执行任何复制。

于 2012-11-08T14:04:58.490 回答
0

我将假设DMatrix需要超过 8 个字节 ( sizeof(DMatrix) > 8),因为编译器可能会使用不同的技术来返回小类。

用代码

int main() {
    //...
    DMatrix d;
    d = someFunc();
    //...
}

大多数编译器会将该代码“重写”为类似于

DMatrix d;
DMatrix __retval;
someFunc(__retval);
d = __retval;

同时,someFunc被“重写”为类似的东西

void someFunc(DMatrix& __retval) {
    DMatrix mymat;
    /* Some operations on this matrix */
    // move/copy mymat into __retval
}

因此,对于大型类,大多数编译器将该类型的返回值转换为函数的参数,并为调用函数中的返回值分配存储空间。

在上面的解释中,我没有利用任何存在的优化可能性,所以它说明了“最坏情况”的行为。


为了能够从函数返回类型,该类型至少需要有一个移动构造函数(仅限 C++11)或复制构造函数。除非您的类型显式管理某些资源(例如,带有 new/delete 的内存),否则通常不需要自己编写这些资源,因为编译器会为您生成合适的资源。

于 2012-11-08T15:16:16.460 回答