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 中缺少&
。 (out
应该是参考...)
这取决于您的编译器是否支持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 引用,则不能。这只是语言规则之一。所以这种行为很像按值传递,如果你愿意,你可以传递一个临时对象。 (由于mutable
和const_cast
,对被调用者修改对象也有一些边际保护。但实际上很少见。)【参考方案4】:
我的建议是编写代码,以便客户端使用尽可能直观。
如果 - 通常情况下 - 你判断它是按值返回,那么如果你的系统对性能至关重要,并且你发现编译器没有很好地优化特定的返回值 - 即使是在合理的最高值 优化级别您可以在检查任何相关的命令行选项或实现 RVO 的编译器提示之后使用,并在可行时考虑替代编译器 - 理想情况下是一个 C++11 编译器,该编译器受益于始终高效的移动语义,然后才更改特定的问题点以通过引用接受返回值。
【讨论】:
以上是关于C++ 引用与返回值的主要内容,如果未能解决你的问题,请参考以下文章