1

Consider the following example that takes a msg and posts it asynchronously.

    void sendMessage(std::string msg) {
        runAsync<void>([msg = std::move(msg)] {
            onPostMessage(cookie, msg.c_str());
        });
    };

Would the following be faster?

void sendMessage(std::string&& msg) {

What would be the best options at the calling site?

    auto msg = ...
    postMessage(msg);

or

    auto msg = ...
    postMessage(std::move(msg));

Note that msg isn't needed after the call anymore.

Will the compiler automatically detect that I am not using msg anymore after the call and "move" it?

user3612643
  • 5,096
  • 7
  • 34
  • 55
  • EDIT: Ah you tagged with only C++14, nevermind... original comment: I think `std::string_view` would be better than r-value reference to `std::string`. But otherwise they should be equivalent in speed I reckon (the string will materialize only when actually used as per C++17 rules). However the original version is better because it works fro both l-value and r-value (easier to use). Copy-elision will likely take place as well. – Resurrection Sep 09 '20 at 08:00
  • The point is that at the calling site, the `msg` isn't required after posting it, so I am trying to find the most efficient way to pass it down to finally move it into the capture... – user3612643 Sep 09 '20 at 08:02
  • 3
    If you are limited to C++14 than it will vary by compiler as there is no guaranteed copy elision or move elision. However even so I would say using value and std::move is better. Alternatively you may try making the `msg` const that could lead to some optimizaton as well. But there are no guarantees by the standard until C++17... – Resurrection Sep 09 '20 at 08:08
  • How would making it `const std::string msg` affect the final move into the capture? – user3612643 Sep 09 '20 at 08:09
  • If you take by value you need to `std::move` at the calling site to avoid a copy if you are passing in an lvalue as in your example. If you use `std::string&&` as parameter you enforce that an rvalue is passed at the calling site, which could be good depending on your use case. – super Sep 09 '20 at 08:23
  • Try it in compiler explorer. https://godbolt.org/ – schteppe Sep 09 '20 at 13:22
  • Can you just pass the initializer for `msg` directly to `sendMessage`? – Davis Herring Sep 09 '20 at 13:36
  • 1
    @user3612643 answers: yes, second, no. – B0FEE664 Sep 09 '20 at 14:05
  • Does this answer your question? [Are the days of passing const std::string & as a parameter over?](https://stackoverflow.com/questions/10231349/are-the-days-of-passing-const-stdstring-as-a-parameter-over) – MicroVirus Sep 09 '20 at 15:11

1 Answers1

1

I would use the following solution:

void sendMessage(std::string&& msg) {
    runAsync<void>([msg = std::move(msg)] {
        onPostMessage(cookie, msg.c_str());
    });
};

and at the calling site:

auto msg = ...
sendMessage(std::exchange(msg, {}));
B0FEE664
  • 191
  • 5
  • Why exchange and not move? – user3612643 Sep 09 '20 at 14:21
  • 1
    @user3612643 After std::move the msg becomes valid, but in unspecified state. So, to avoid inadvertent use of the variable after sendMessage, I prefer std::exchange. See (8) at [link](https://en.cppreference.com/w/cpp/string/basic_string/basic_string) – B0FEE664 Sep 09 '20 at 14:36