从c++函数中返回多个值的首选方法是什么?例如,假设有一个函数对两个整数进行除法并同时返回商和余数。我经常看到的一种方法是使用引用形参:

void divide(int dividend, int divisor, int& quotient, int& remainder);

一种变体是返回一个值,并通过引用形参传递另一个值:

int divide(int dividend, int divisor, int& remainder);

另一种方法是声明一个结构体来包含所有的结果并返回:

struct divide_result {
    int quotient;
    int remainder;
};

divide_result divide(int dividend, int divisor);

这些方法中是否有一种通常是首选的,还是有其他的建议?

编辑:在实际代码中,可能会有两个以上的结果。它们也可能是不同类型的。


当前回答

替代方案包括数组、生成器和控制反转,但在这里不适用。

有些(例如微软在历史上的Win32)倾向于使用引用参数来简化,因为它很清楚由谁分配以及它在堆栈上的外观,减少了结构的扩散,并允许成功的单独返回值。

“纯”程序员更喜欢结构体,假设它是函数值(就像这里的情况一样),而不是函数偶然接触的东西。如果您有一个更复杂的过程,或者带有状态的东西,您可能会使用引用(假设您有不使用类的理由)。

其他回答

替代方案包括数组、生成器和控制反转,但在这里不适用。

有些(例如微软在历史上的Win32)倾向于使用引用参数来简化,因为它很清楚由谁分配以及它在堆栈上的外观,减少了结构的扩散,并允许成功的单独返回值。

“纯”程序员更喜欢结构体,假设它是函数值(就像这里的情况一样),而不是函数偶然接触的东西。如果您有一个更复杂的过程,或者带有状态的东西,您可能会使用引用(假设您有不使用类的理由)。

使用结构体或类作为返回值。使用std::pair可能暂时有效,但是

如果你决定以后要返回更多信息,这是不灵活的; 从函数头中的声明来看,不太清楚返回的是什么以及返回的顺序。

Returning a structure with self-documenting member variable names will likely be less bug-prone for anyone using your function. Putting my coworker hat on for a moment, your divide_result structure is easy for me, a potential user of your function, to immediately understand after 2 seconds. Messing around with ouput parameters or mysterious pairs and tuples would take more time to read through and may be used incorrectly. And most likely even after using the function a few times I still won't remember the correct order of the arguments.

如果你通过引用函数返回一个值,编译器不能存储在寄存器当调用其他函数,因为从理论上讲,第一个函数可以保存变量的地址传递给它的全局变量,和任何subsecuently称为功能可能改变它,所以编译器会有(1)将值从寄存器保存到内存之前调用其他函数和(2)重读的时候需要从内存后再任何这样的调用。

如果通过引用返回,程序的优化将受到影响

如果只有几个返回值,我只会通过引用来做,但对于更复杂的类型,你也可以这样做:

static struct SomeReturnType {int a,b,c; string str;} SomeFunction()
{
  return {1,2,3,string("hello world")}; // make sure you return values in the right order!
}

如果返回类型只是一个临时返回类型,则使用“static”将返回类型的范围限制在这个编译单元。

 SomeReturnType st = SomeFunction();
 cout << "a "   << st.a << endl;
 cout << "b "   << st.b << endl;
 cout << "c "   << st.c << endl;
 cout << "str " << st.str << endl;

这绝对不是最漂亮的方法,但它是有效的。

我倾向于在这样的函数中使用out-val,因为我坚持函数返回成功/错误代码的范式,并且我喜欢保持统一。