开发者

C++ references vs return values

开发者 https://www.devze.com 2023-01-29 22:58 出处:网络
I understand the principle point of references is to avoid making copies of large structures, but what if a function you\'re writing itself creates a large structure? Is it less efficient (or are you

I understand the principle point of references is to avoid making copies of large structures, but what if a function you're writing itself creates a large structure? Is it less efficient (or are you more likely to run out of memory) to create the variable locally, then return it, than you are to pass the destination object as a reference, and fill it from within the function?

I can't seem to phrase that well, so a concret开发者_Python百科e example: Suppose a function takes a string, and returns a vector of each line in the string. Is there a material advantage to the function:

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

over:

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

Thanks for any help, Wyatt


The first example should presumably be more like one of these two:

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

The second style is often more convenient, and can in theory be made mostly as efficient as the first one:

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

Whether this is seen in practice depends on the compiler, optimization levels, and whether the compiler can spot the opportunity in the first place.

Whilst I don't speak for everybody, I've never actually managed to get compilers to take advantage of RVO, even with simple objects that don't do anything fancy. So I therefore personally recommend the first approach, because you are guaranteed to get the desired behaviour, on every compiler, and (which seems relevant for me...) for every programmer's code -- i.e., that the object created to hold the return value is filled in directly by the called function, without any extra copies.

(The cost of default-constructing the result object, which is something that could potentially be avoided were RVO to be taken advantage of, is usually not significant compared to the copy the compiler might be unable to avoid.)

Another point to note would be that if attempting to avoid unnecessary copies, passing objects by const reference instead of by value is often a good idea, e.g.:

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


That depends on if your compiler supports return value optimization (most do) and if the code qualifies for that optimization.


Well, in your specific case (filling a container with values) I would go for an input iterator approach. But in all other cases (like a complicated string generation or some calculations) I wouldn't care about possible performance hits and trust RVO (see Jim's answer) and the compiler to optimize it like it should. If it becomes a bottleneck (profile!), change it of course!


My advice is to write the code so that the client usage is as intuitive as possible.

If - as is usually the case - you judge that to be returning by value, then if your system is performance critical and you find a particular return value is not being optimised nicely by your compiler - even at the highest reasonable optimisation level you can use and after checking for any relevant command line options or compiler tips on achieving RVO, and considering alternative compilers if practical - ideally a C++11 compiler that benefits from always-efficient move semantics, only then change the specific problematic spot to accept the return value by reference.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号