C++ 函数返回与函数设置指针

Posted

技术标签:

【中文标题】C++ 函数返回与函数设置指针【英文标题】:C++ Functions returnings vs Functions setting a pointer 【发布时间】:2015-10-20 17:25:58 【问题描述】:

我想知道返回值的函数和给指针设置值的函数的区别,例如:

指针:

int myVal;
ptr_multiply(5, 5, &myVal);
cout << myVal << endl; //Output: 25

返回:

int myVal = rtn_multiply(5, 5);
cout << myVal << endl; //Output: 25

我的问题集中在创建函数时选择什么方法以及为什么,以及我们可以在每个方法中找到哪些优点/缺点。

【问题讨论】:

我在 90 年代中期的大学课堂上问了这个问题。教授告诉我,一般来说,一个好的规则是如果函数不改变状态(您正在调用方法的对象或程序全局状态本身的状态)并设置指针(或引用),则使用 return如果是的话。我不记得为什么,但我记得他是形式规范(特别是 Z 语言)方面的专家,所以这可能与此有关。 【参考方案1】:

可读性是函数通常返回您期望它们返回的主要原因的主要原因。但是,由于这是非常主观的,我建议您在项目中努力保持一致性。

如果您希望函数返回多个事物而不是将它们全部组合在一个结构中以便返回它们,另一种方法是在输出参数中返回它们。

【讨论】:

要返回多个东西而不必为此创建结构,您可以使用 std::tuple,它与 std::tie 配合得很好【参考方案2】:

如果您要返回大量数据,那么您可能会遇到性能瓶颈。原因是返回值必须被复制。

但在大多数情况下,您不必担心这一点,因为现代编译器能够自动内联这样的事情。

旁注:在 C++ 中尽量避免使用裸指针(使用引用、智能指针)

【讨论】:

RVO 开始发挥作用。另外,如果你把一个输出参数传给一个函数,你是不是也得把数据复制进去? 严格的输出参数将是未初始化的内存,并且将使用placement-new。我想可能会很快。但我猜基本上和 RVO 一样【参考方案3】:

使用“指针”方法的一个优点是您可以通过传入非常量引用或指针来获得多个“返回”值。例如:

int output1;
int output2;
get_values("input", &output1, &output2)

【讨论】:

您可以使用tietuple 为返回值执行此操作。【参考方案4】:

您可以返回成功/失败:

int v = -1;
if(ToInt("wibble",&v))
  // do something with v

将失败,因为 "wibble" 无法转换为 int。

另一个有用的地方是函数不必改变v:

int v = previousValue;
UpdateIfNewValueFound( &v )

【讨论】:

你仍然可以使用exception而不是bool来暴露失败。【参考方案5】:

返回值。对于现代编译器,应该两者之间的性能几乎没有差异,但返回值有几个优点:

根据定义,这是 函数 应该做的(即函数从域映射到共域)。 它是自我记录的;如果我使用的是不熟悉的 API,除非有良好的文档,否则如果在参数集中返回值,可能会混淆输入/输出是什么。返回值没有歧义,并且需要较少的文档记录。

它更易于使用 - 所需的行数可以减半!比较

int r = f();

int r;
f(&r);

它可以让你成为一个更好的程序员;您必须付出更多努力从函数返回多个值(例如,通过structpair,而不是添加另一个参数)。如果你发现你需要经常这样做,额外的努力可能会迫使你更仔细地考虑你的代码设计 - 通常最好让一个函数只做/返回一件事。

【讨论】:

【参考方案6】:

另一个区别是堆栈或堆。

返回值位于堆栈顶部。指针变量位于堆中。

例如(演示堆栈返回的无意义递归代码):

typedef std::array<int,1000> KByte;
KByte tmp;

KByte f(int nr) 
    if (nr == 1)  tmp[nr]=nr; return tmp; 
    else  tmp[nr]=nr; return f(nr-1); ;


void f2(int nr, KByte& ret) 
    if (nr == 1)  ret[1]=1; 
    else  ret[nr]=nr; f2( nr-1, ret ); 
;

打电话

KByte t = f(999); /* Stack error */

应该给你一个堆栈大小错误,因为堆栈上的 1000 KB (1GB) 太多了。

打电话

KByte t2;
f2( 999, t2 );

应该没有堆栈问题。 (它也使用递归深度 1000,但不会将返回值放在堆栈上。

【讨论】:

以上是关于C++ 函数返回与函数设置指针的主要内容,如果未能解决你的问题,请参考以下文章

如何使函数返回指向函数的指针? (C++)

C++ 把引用作为函数返回值

从函数 C++ 正确传递指针

struct 的指针作为 c++ dll 函数的返回值

C++性能系列之函数与函数参数的几个原则

C++指针问题,请问如何定义一个返回值为结构体指针数组的函数?