0

Example code:

class Thingy
{
public:
    void doStuff(std::string&);
    std::string doStuff();
};

void Thingy::doStuff(std::string& str) {
    str = "stuff";
}

std::string Thingy::doStuff() {
    return "stuff";
}

int main(int argc, const char* args[])
{
    std::string name;
    Thingy thingy;
    thingy.doStuff(name);
    std::cout << name << " " << thingy.doStuff() << std::endl;
}

Specifically for strings, is either approach more efficient, and is that efficiency "worth it" to warp the readability or consistency of your code? (For example, I'd prefer not to create the name variable if I don't have to)

And is the fact that this is (at the end of the day) a string constant relevant to this discussion?

deworde
  • 2,679
  • 5
  • 32
  • 60
  • 2
    Essentially the answer is the same as for [returning a `std::vector`](http://stackoverflow.com/questions/22655059/why-it-is-ok-to-return-vector-from-function/22655120#22655120). – πάντα ῥεῖ Aug 25 '15 at 13:21
  • 2
    I prefer returning an `std::string` as it's more readable. Your compiler is very likely to perform RVO (return value optimization) and even if it doesn't, the string will be constructed with its move constructor. It won't be dramatically less efficient. – Caninonos Aug 25 '15 at 13:23
  • 1
    *that this is [...] a string constant relevant to this discussion*. As long as the return type is `std::string` and not `const std::string &`, the difference is not relevant as in the end you need to construct a mutable string from a constant char array. – dhke Aug 25 '15 at 13:30
  • @πάνταῥεῖ Which answers my question about whether "strings are special". But I've definitely seen a tendency to pass strings as return types and vectors as output parameters (possibly because strings are more likely to be short) – deworde Aug 25 '15 at 14:39

3 Answers3

5

Copy on write semantics on a std::string are no longer allowable so, ostensibly, you might think that returning a string by value is computationally expensive due to a deep copy being taken.

But, in C++03, a good compiler will elide the deep copy. In C++11, the move constructor will be called. No excess value copy will be taken.

Personally I dislike the pattern of passing a non-const reference to a function as it's not immediately obvious to the caller that the parameter is modified. You also can't pass an anonymous temporary to such a function (not that you'd want to do that of course in this case). Writing the function to return the string gives you all pros without the cons.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 2
    As a matter of fact, even in C++11 the copy will be elided (if it can be, of course) rather than calling move contstructor. Only when elision fails move constructor will be used. – SergeyA Aug 25 '15 at 13:33
  • @SergeyA: are you sure? Is there a standard ref for this? – Bathsheba Aug 25 '15 at 13:38
  • 2
    I am pretty sure :). As for the standard, of course there is none, since optimizations are not specified in standard. But this is the actual behaviour of all C++11 compiler I know of. As a matter of fact, it's hard to imagine otherwise, as this would imply that C++11 will perform worse than C++03 - since even move constructor is more expensive than no constructor. – SergeyA Aug 25 '15 at 13:41
  • Note that with small strings a move may be no cheaper than a copy due to the small string optimization. – Chris Drew Aug 25 '15 at 13:47
0

Returning string approach is more efficient since it worth only one string construction (due to RVO). As for me it's more understandable too.

Megamozg
  • 975
  • 9
  • 15
  • I don't think returning by value is always more efficient (in this specific case, it might be, although some compilers might also inline the "by reference call" and output the exact same code). On more complicated functions, RVO might not be performed (depending on the compiler) and the move constructor might be used instead. Anyway, the efficiency difference is minimal so it doesn't really matter. – Caninonos Aug 25 '15 at 13:30
  • @Caninonos In C++03, with no move constructor, does that assessment change? – deworde Aug 25 '15 at 15:39
  • 1
    @deworde In C++03 RVO might still be performed as long as the function isn't too complex (again, depending on the compiler). However, if it doesn't, the copy constructor will be called instead (and such a call might be expensive for big vectors or strings). In that case passing a reference (and mutating it) is indeed more efficient and might be preferred (well in your example, the function is so simple that most compilers will perform RVO, so it doesn't really matter). (Edit: personnally, I'd avoid C++03 and return values if possible rather than mutating a reference in my functions) – Caninonos Aug 25 '15 at 15:56
0

If the string are not long then return by value is not that bad! Especially that it will allow to concatenate things using "." operator. Moreover, now in C++11, when the move constructor is presented, the performance issue related to return by value has significantly decreased.

Alex Lop.
  • 6,810
  • 1
  • 26
  • 45