简体   繁体   中英

rvalue for a std::string parameter

What's the difference in practice between LVALUE and RVALUE in the following code when I pass the text? I mean, in this specific case of a string (where the string is a string literal), is there any benefit of using RVALUE (&&)?

void write_Lvalue(const std::string &text) {
    //...
}

void write_Rvalue(const std::string &&text) {
    //...
}

int main() {
    write_Lvalue("writing the Lvalue");
    write_Rvalue("writing the Rvalue");
}

There's no benefit in this case. write_Rvalue will only accept an rvalue. and write_Lvalue will only accept an lvalue.

When you pass a string literal a temporary std::string will be constructed from the string literal. The rvalue variant can already bind to this because you're already passing a temporary and the lvalue variant can bind to the temporary because it's const .

This for example, will not compile:

void write_Lvalue(const std::string &text) {
    //...
}

void write_Rvalue(const std::string &&text) {
    //...
}

int main() {
    std::string a = "hello";
    write_Rvalue(a);
}

because we're trying to pass an lvalue a to a function only accepting an rvalue.

The benefit that can be gained with rvalue types is that they can be moved from. There's a great post on why moving can be faster here .

Making your rvalue const defeats the purpose of it though as said in the comments, because it can't be moved from anymore.

First, constant rvalue reference are not really useful, since you cannot move them. Moving value need mutable references to work.

Let's take your corrected example:

void write_lvalue(std::string const& text) {
    //...
}

void write_rvalue(std::string&& text) {
    //...
}

int main() {
    write_lvalue("writing the Lvalue");
    write_rvalue("writing the Rvalue");
}

In this case, the two are completely equivalent . In these two case, the compiler has to create a string and send it by reference:

int main() {
    // equivalent, string created
    // and sent by reference (const& bind to temporaries)
    write_lvalue(std::string{"writing the Lvalue"}); 

    // equivalent, string created
    // and sent by reference (&& bind to temporaries)
    write_rvalue(std::string{"writing the Rvalue"});
}

So why have function that takes rvalue references?

It depends on what you do with the string. A mutable reference can be moved from:

std::string global_string;

void write_lvalue(std::string const& text) {
    // copy, might cause allocation
    global_string = text;
}

void write_rvalue(std::string&& text) {
    // move, no allocation, yay!
    global_string = std::move(text);
}

So why using rvalue reference at all? Why not using mutable lvalue reference?

That is because mutable lvalue references cannot be bound to temporaries:

void write_lvalue_mut(std::string& text) {
    // move, no allocation... yay?
    global_string = std::move(text);
}

int main() {
    std::string s = /* ... */;
    write_lvalue_mut(std::move(s)); // fails
    write_lvalue_mut("some text"); // also fails
}

But mutable rvalue reference can be bound to rvalue, as shown above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM