【问题标题】:Returning values from a function : reference vs struct从函数返回值:引用 vs 结构
【发布时间】:2015-12-05 07:57:24
【问题描述】:

我是编程新手,我正在使用这本书学习 C++ 编程语言:编程原理和使用 C++ 的实践。我今天来到这里,是因为在第 8 章的最后,作者专注于函数,并提出了一个练习,让学习者思考一个问题的更好解决方案:

编写一个函数,找出向量参数的最小和最大元素,并计算均值和中位数。不要使用全局变量。要么返回包含结果的struct,要么通过引用参数将它们传回。您更喜欢这两者中的哪一个返回多个值,为什么?

现在,通常我不会定义一个函数来执行多个操作,但在这种情况下,我必须只创建一个函数并考虑如何返回多个值。我的第一种方法是创建一个采用如下引用参数的函数:

void my_func(
    vector<double>& numbers,
    double& min,
    double& max,
    double& mean,
    double& median
);

但是继续编写程序,我开始认为这个解决方案使用了太多参数,也许建议的其他解决方案(使用struct)会更好。你会如何使用struct 来解决这个问题?如何从函数返回多个值?

【问题讨论】:

  • 你不会从一个函数中返回多个值,这是不可能的。相反,您返回 一个 结构实例,其中包含多个成员(例如 minmax 等成员)。
  • 在有用且可能的情况下使用encapsulation。在这里它是可能且有用的,因此您应该在此处使用答案中建议的结构(例如统计信息)。
  • 如果你使用的是 c++11,你可能想看看std::tuple

标签: c++ struct parameter-passing return-value


【解决方案1】:

使用struct 解决这个问题很简单:为返回类型定义一个struct,然后使用它,如下所示:

struct stats {
    double min;
    double max;
    double mean;
    double median;
};
stats my_func(vector<double>& numbers) {
    stats res;
    ...
    res.min = ...
    res.max = ...
    res.mean = ...
    res.median = ...
    return res;
}

这里的权衡是,为了换取更简单的函数签名,函数的用户需要一个一个地提取他们想要的元素。

但是如果结构真的很复杂并且复制的成本变得太昂贵怎么办?

与函数的“有效负载”CPU 时间相比,复制需要一个极端大小的结构变得过于昂贵。最重要的是,当您执行此操作时,C++ 优化器通过采用copy elisionreturn value optimization 策略来降低复制成本:

stats s = my_func(numbers);

struct 变得如此巨大以至于您不想复制它时,可以像这样结合这两种方法:

void my_func(vector<double>& numbers, stats& res);

【讨论】:

  • @PoojaNilangekar 谢谢,这是一个很好的编辑。不幸的是,它被自动拒绝了,因为我自己正在编辑答案。感谢您发现此复制粘贴错误!
  • 从我学到的基础知识中,我知道当函数在您的示例中返回一个值时,会创建一个 return_value 的副本。但是如果结构真的很复杂并且复制的成本变得太昂贵怎么办?
  • @pieroborrelli 使用移动语义和复制省略的机会很大,您实际上不会复制。特别是如果你从函数返回初始化一个变量。
【解决方案2】:

好吧,你只返回一个结构。

struct res {
   double min; 
   double max;
   double mean;
   double median;
};

res my_func(vector<double>& numbers) {
    res result;
    // do stuff, put result in in result.min etc

    return result;
}

另一个可以用类似的方式完成:

void my_func(vector<double>& numbers,
             res& result)
{
    // the same code except no return value

    return;
}

现在对于您任务中的问题(我不会回答 - 因为这是您喜欢的问题),我想提一下技术差异是什么。

当返回一个结构时,这意味着您可能会创建一个result 结构的临时副本(它还可能导致两个对象res 一个供调用者使用,一个供my_func 使用)。而另一种方法意味着您传递给函数本质上是地址放置结果的位置。有了一个“好的”实现,你最终可能会得到相同的代码。

【讨论】:

  • 使用移动语义和复制省略的机会很大,您实际上不会复制。特别是如果你从函数返回初始化一个变量。
  • 这个概率已经改变了,我把它从“可能”改成了“可能”,表示这些天不太可能。
【解决方案3】:

声明struct

struct stats {
   double min;
   double max;
   double mean;
   double median;
};

然后

stats my_func(vector<double>& numbers);

函数会是这样的

stats my_func(vector<double>& numbers) {
    stats return_value;

     // Fill in the structure

    return return_value;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    • 2020-03-03
    相关资源
    最近更新 更多