103

Possible Duplicate:
Are the days of passing const std::string & as a parameter over?

Should I pass std::string by value or by reference (to a un-inlined function) if move semantics is supported? And what about implementations using small string optimization (SSO)?

Community
  • 1
  • 1
Nordlöw
  • 11,838
  • 10
  • 52
  • 99
  • 6
    What are you going to do with the string in the function? – linuxuser27 May 28 '12 at 19:47
  • @linuxuser27: Aah, good question. The answer depends on that of course... In some case I just read it, in others I concatenate it together with directories to construct paths. I believe I should pass by value when I want to modify it, to make move constructors kick in. What about read-only cases---by constant reference? – Nordlöw May 28 '12 at 19:50

3 Answers3

187

There are multiple answers based on what you are doing with the string.

1) Using the string as an id (will not be modified). Passing it in by const reference is probably the best idea here: (std::string const&)

2) Modifying the string but not wanting the caller to see that change. Passing it in by value is preferable: (std::string)

3) Modifying the string but wanting the caller to see that change. Passing it in by reference is preferable: (std::string &)

4) Sending the string into the function and the caller of the function will never use the string again. Using move semantics might be an option (std::string &&)

linuxuser27
  • 7,183
  • 1
  • 26
  • 22
  • Case 3) is only neccessary if the `std::string` implementation doesn't support move semantics right? – Nordlöw May 28 '12 at 19:55
  • 1
    @Nordlöw Not really. Move semantics are interesting because they are moving the data not copying it. In the above case the move semantics would move the `char *` in the `std::string` from the caller function to the called function. If you use move semantics to pass in the value the string will no longer be in the caller function unless you pass it back out. See the link above talking about move semantics. – linuxuser27 May 28 '12 at 19:59
  • 24
    #4 is unnecessary, as this is something that can and should be taken care of on the caller's side by using `std::move` on his argument and invoking the by-value version. – Benjamin Lindley May 28 '12 at 21:43
  • @BenjaminLindley: See http://ideone.com/OYu0Ux . What happens when I directly pass string literals to function that has arguments of type const std::string&. Does the compiler create 2 temporary std::string objects & bind that to two const reference parameters respectively behind the scenes for rvalues? – Destructor Jan 31 '16 at 07:05
  • 4
    @BenjaminLindley Not at all, `&&` prevents accidentally passing the argument by copy. – Emil Laine Mar 06 '16 at 02:17
  • 2
    @Destructor It constructs a `std::string` from the string literal and passes it as an argument. Then it copy constructs the member string from the argument. So two allocations and two O(n) array copy operations (per argument). You should take the params by value and `std::move` them into the members. That way it would be only one allocation, one O(n) array copy, and one O(1) move per argument. – Emil Laine Mar 06 '16 at 02:26
28

Check this answer for C++11. Basically, if you pass an lvalue the rvalue reference

From this article:

void f1(String s) {
    vector<String> v;
    v.push_back(std::move(s));
}
void f2(const String &s) {
    vector<String> v;
    v.push_back(s);
}

"For lvalue argument, ‘f1’ has one extra copy to pass the argument because it is by-value, while ‘f2’ has one extra copy to call push_back. So no difference; for rvalue argument, the compiler has to create a temporary ‘String(L“”)’ and pass the temporary to ‘f1’ or ‘f2’ anyway. Because ‘f2’ can take advantage of move ctor when the argument is a temporary (which is an rvalue), the costs to pass the argument are the same now for ‘f1’ and ‘f2’."

Continuing: " This means in C++11 we can get better performance by using pass-by-value approach when:

  1. The parameter type supports move semantics - All standard library components do in C++11
  2. The cost of move constructor is much cheaper than the copy constructor (both the time and stack usage).
  3. Inside the function, the parameter type will be passed to another function or operation which supports both copy and move.
  4. It is common to pass a temporary as the argument - You can organize you code to do this more.

"

OTOH, for C++98 it is best to pass by reference - less data gets copied around. Passing const or non const depend of whether you need to change the argument or not.

Destructor
  • 14,123
  • 11
  • 61
  • 126
emsr
  • 15,539
  • 6
  • 49
  • 62
6

I believe the normal answer is that it should be passed by value if you need to make a copy of it in your function. Pass it by const reference otherwise.

Here is a good discussion: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
  • 2
    content deleted, still available here: http://web.archive.org/web/20120908071416/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value – DanielTuzes Sep 25 '19 at 21:09