rvalue for a std::string parameter
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.
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.