C++ 引用与返回值

Posted

技术标签:

【中文标题】C++ 引用与返回值【英文标题】:C++ references vs return values 【发布时间】:2011-05-24 05:14:43 【问题描述】:

我知道引用的原则是避免复制大型结构,但是如果您编写的函数本身创建了一个大型结构怎么办?与将目标对象作为引用传递并从函数中填充它相比,在本地创建变量然后返回它是否效率较低(或者您更有可能耗尽内存)?

我似乎不能很好地表达,所以一个具体的例子:假设一个函数接受一个字符串,并返回字符串中每一行的向量。该功能是否有物质优势:

void getLines(std::string in, std::vector<std::string>& out);

结束:

std::vector<std::string> getLines(std::string in);

感谢您的帮助, 悦

【问题讨论】:

我认为您在第一个代码 sn-p 中缺少 &amp;。 (out 应该是参考...) out 是一个参考...... 很抱歉,它丢失了,其他人编辑了它。 【参考方案1】:

这取决于您的编译器是否支持return value optimization(大多数支持)以及代码是否符合该优化的条件。

【讨论】:

VC2005 执行 named RVO,这样可以在返回向量时省去您的麻烦(这样您就不必到处构建“惰性”迭代器了)。见msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx 另外请注意,至少有一个编译器 (VC++) 将执行普通的旧 RVO,即使关闭所有优化【参考方案2】:

好吧,在您的特定情况下(用值填充容器)我会采用输入迭代器方法。但是在所有其他情况下(例如复杂的字符串生成或某些计算),我不会关心可能的性能损失并信任 RVO(请参阅 Jim 的回答)和编译器会按应有的方式对其进行优化。如果它成为瓶颈(配置文件!),当然改变它!

【讨论】:

是的,迭代器通常是要走的路。除非你使用虚函数。【参考方案3】:

第一个例子应该更像这两个中的一个:

void getLines(std::string in, std::vector<std::string> &out);
void getLines(std::string in, std::vector<std::string> *out);

第二种风格通常更方便,理论上可以和第一种一样高效:

http://en.wikipedia.org/wiki/Return_value_optimization

这是否在实践中被看到取决于编译器、优化级别以及编译器是否能够首先发现机会。

虽然我并不代表所有人,但我从未真正设法让编译器利用 RVO,即使对于不做任何花哨的简单对象也是如此。因此,我个人推荐第一种方法,因为您可以保证在每个编译器上获得所需的行为,并且(这对我来说似乎相关......)对于每个程序员的代码——即,为保存返回而创建的对象value 由被调用函数直接填写,没有多余的副本。

(与编译器可能无法避免的副本相比,默认构造结果对象的成本(如果利用 RVO 可能会避免这种情况)通常并不显着。)

要注意的另一点是,如果试图避免不必要的复制,通过 const 引用而不是通过值传递对象通常是一个好主意,例如:

void getLines(const std::string &in, std::vector<std::string> &out);
void getLines(const std::string &in, std::vector<std::string> *out);

【讨论】:

我理解通过引用传递输入的实用程序,这只是一个疏忽,但为什么是 const 引用? 如果函数未修改其引用对象,则每个引用函数参数都应为 const。这应该是第二天性。帮助编译器优化,帮助程序员理解和使用函数。 如果函数接受值或 const 引用,您可以传入临时对象,但如果函数接受非 const 引用,则不能。这只是语言规则之一。所以这种行为很像按值传递,如果你愿意,你可以传递一个临时对象。 (由于mutableconst_cast,对被调用者修改对象也有一些边际保护。但实际上很少见。)【参考方案4】:

我的建议是编写代码,以便客户端使用尽可能直观。

如果 - 通常情况下 - 你判断它是按值返回,那么如果你的系统对性能至关重要,并且你发现编译器没有很好地优化特定的返回值 - 即使是在合理的最高值 优化级别您可以在检查任何相关的命令行选项或实现 RVO 的编译器提示之后使用,并在可行时考虑替代编译器 - 理想情况下是一个 C++11 编译器,该编译器受益于始终高效的移动语义,然后才更改特定的问题点以通过引用接受返回值。

【讨论】:

以上是关于C++ 引用与返回值的主要内容,如果未能解决你的问题,请参考以下文章

c++ 函数返回引用问题

C++ 对象作为返回值:复制还是引用?

为啥在返回右值引用时给出 C++ 编译器警告?

C++:从实例出发,搞定引用在不同场景的用法

在 C++ 中将右值引用转换为临时参数到 const 左值返回的正确方法

C++ 函数返回引用