从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);

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

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


当前回答

c++ 17,使用std::make_tuple,结构化绑定和尽可能多的auto:

#include <tuple>

#include <string>
#include <cstring>

auto func() {
    // ...
    return std::make_tuple(1, 2.2, std::string("str"), "cstr");
}

int main() {
    auto [i, f, s, cs] = func();
    return i + f + s.length() + strlen(cs);
}

使用-O1完全优化:https://godbolt.org/z/133rT9Pcq -O3只需要优化std::string: https://godbolt.org/z/Mqbez73Kf

在这里:https://godbolt.org/z/WWKvE3osv,您可以看到GCC将所有返回值打包在一个内存块中(rdi+N), pod样式,证明没有性能损失。

其他回答

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

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

我想说,没有首选方法,这完全取决于你将如何处理响应。如果结果将在进一步处理中一起使用,那么结构是有意义的,如果不是,我倾向于将then作为单独的引用传递,除非函数将用于复合语句中:

X =除(X, y, z) +除(a, b, c);

我经常选择在参数列表中通过引用传递“结构”,而不是通过返回新结构的拷贝开销(但这是汗流浃背的小事)。

无效除(整数被除数,整数除数,答案和ans)

我们的参数令人困惑吗?作为引用发送的形参表明值将发生变化(与const引用相反)。合理的命名也可以消除混淆。

而不是返回多个值,只返回其中一个,并在所需的函数中引用其他的eg:

int divide(int a,int b,int quo,int &rem)
std::pair<int, int> divide(int dividend, int divisor)
{
   // :
   return std::make_pair(quotient, remainder);
}

std::pair<int, int> answer = divide(5,2);
 // answer.first == quotient
 // answer.second == remainder

Std::pair本质上是你的结构解决方案,但是已经为你定义好了,并且可以适应任何两种数据类型。

OO解决方案是创建一个比率类。它不需要任何额外的代码(会节省一些代码),会明显更干净/清晰,并且会给你一些额外的重构,让你也可以清理这个类之外的代码。

实际上,我认为有人建议返回一个结构,这是足够接近,但隐藏的意图,这需要一个充分考虑的类与构造函数和一些方法,事实上,你最初提到的“方法”(作为返回对)应该最有可能是这个类的成员,返回自己的实例。

我知道你的例子只是一个“例子”,但事实是,除非你的函数做的比任何函数都要多,如果你想让它返回多个值,你几乎肯定会错过一个对象。

不要害怕创建这些小的类来做小的工作——这就是OO的神奇之处——你最终会分解它,直到每个方法都非常小而简单,每个类都非常小而可理解。

另一件事应该是一个错误的指示器:在OO中,你基本上没有数据——OO不是传递数据,一个类需要在内部管理和操作它自己的数据,任何数据传递(包括访问器)都是一个迹象,表明你可能需要重新考虑一些事情。