我理解引用的原则是避免复制大型结构,但是如果你自己编写的函数创建了一个大型结构呢?是否效率较低(或者你是否更有可能耗尽内存)在本地创建变量,然后返回它,而不是将目标对象作为参考传递,并从函数中填充它?
我似乎无法说得那么好,所以一个具体的例子:假设一个函数接受一个字符串,并返回字符串中每一行的向量。该功能是否有实质性优势:
void getLines(std::string in, std::vector<std::string>& out);
在:
std::vector<std::string> getLines(std::string in);
感谢您的帮助, 悦
答案 0 :(得分:5)
这取决于您的编译器是否支持return value optimization(大多数情况下)以及代码是否符合该优化条件。
答案 1 :(得分:5)
第一个例子应该更像是这两个中的一个:
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,即使对于没有做任何花哨的简单对象。因此,我个人推荐第一种方法,因为您可以保证在每个编译器上获得所需的行为,并且(对我来说似乎相关...)对于每个程序员的代码 - 即,为保持返回而创建的对象值由被调用的函数直接填充,没有任何额外的副本。
(默认构造结果对象的成本,这是可以避免使用的RVO,与编译器可能无法避免的副本相比,通常并不重要。)
需要注意的另一点是,如果试图避免不必要的副本,通过const引用而不是按值传递对象通常是个好主意,例如:
void getLines(const std::string &in, std::vector<std::string> &out);
void getLines(const std::string &in, std::vector<std::string> *out);
答案 2 :(得分:1)
好吧,在你的具体情况下(用一个容器填充值),我会选择输入迭代器方法。但在所有其他情况下(如复杂的字符串生成或一些计算)我不关心可能的性能命中和信任RVO(参见Jim的答案)和编译器来优化它应该如此。如果它成为瓶颈(个人资料!),当然要改变它!
答案 3 :(得分:1)
我的建议是编写代码,以便客户端使用尽可能直观。
如果 - 通常就是这种情况 - 你判断是按值返回,那么如果你的系统性能至关重要并且你发现你的编译器没有很好地优化特定的返回值 - 即使是最合理的优化级别你可以使用和检查任何相关的命令行选项或编译器提示实现RVO,并考虑替代编译器,如果可行 - 理想情况下 C ++ 11 编译器受益于始终高效的移动语义,然后才更改特定的有问题的点以通过引用接受返回值。