当我们在函数内部使用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 ++中编写更好的类。可能需要将其作为一个单独的问题。
答案 0 :(得分:1)
您应该实现一个复制构造函数,但要注意这实际上是一个有趣的场景,您可能会看到二进制文件的“调试”版本与“发布”版本之间存在语义差异。大多数编译器都会优化对复制构造函数的调用,并在此实例中执行return value optimization。在这种情况下,编译器特别允许通过规范对复制构造函数执行此操作。
尝试在复制构造函数中打印一些内容,您会发现在运行发行版时它不会被打印,但它在调试版本中会打印出来。
此外,如果你正在使用C ++ 11,那么当你返回mymat时,mymat将会被称为rvalue(一个临时对象)。在C ++ 11中可以声明move constructor以及复制构造函数,它将显式地将对象移动到外部作用域而不执行任何复制。
答案 1 :(得分: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
}
因此,对于大型类,大多数编译器将该类型的返回值转换为函数的参数,并为调用函数中的返回值分配存储空间。
在上面的解释中,我没有使用任何存在的优化可能性,因此它说明了“最坏情况”的行为。
为了能够从函数返回一个类型,该类型至少需要一个move-constructor(仅限C ++ 11)或copy-constructor。 除非你的类型明确地管理了一些资源(例如,使用new / delete的exaple,内存),通常不需要自己编写,因为编译器会为你生成一个合适的资源。