std::string 参数的右值
rvalue for a std::string parameter
下面代码中传文时LVALUE和RVALUE在实践中有什么区别?
我的意思是,在字符串的这种特定情况下(字符串是字符串文字),使用 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");
}
在这种情况下没有任何好处。 write_Rvalue
将只接受右值。 write_Lvalue
将只接受左值。
当你传递一个字符串文字时,一个临时的 std::string
将从字符串文字构造。右值变量已经可以绑定到这个,因为你已经传递了一个临时变量,左值变量可以绑定到临时变量,因为它是 const
.
这个例子,不会编译:
void write_Lvalue(const std::string &text) {
//...
}
void write_Rvalue(const std::string &&text) {
//...
}
int main() {
std::string a = "hello";
write_Rvalue(a);
}
因为我们试图将左值 a
传递给只接受右值的函数。
右值类型的好处是它们可以被移动。关于为什么移动可以更快 here。
有一个很好的 post
使你的右值 const
违背了它的目的,尽管如评论中所述,因为它不能再移动了。
首先,常量右值引用并不是很有用,因为你不能移动它们。移动值需要可变引用才能工作。
让我们举个更正后的例子:
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");
}
在这种情况下,两者完全等价。在这两种情况下,编译器必须创建一个字符串并通过引用发送它:
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"});
}
那么为什么要有接受右值引用的函数呢?
这取决于您对字符串的处理方式。可以从以下位置移动可变引用:
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);
}
那么为什么要使用右值引用呢?为什么不使用可变左值引用?
那是因为可变左值引用不能绑定到临时对象:
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
}
但是可变右值引用可以绑定到右值,如上所示。
下面代码中传文时LVALUE和RVALUE在实践中有什么区别? 我的意思是,在字符串的这种特定情况下(字符串是字符串文字),使用 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");
}
在这种情况下没有任何好处。 write_Rvalue
将只接受右值。 write_Lvalue
将只接受左值。
当你传递一个字符串文字时,一个临时的 std::string
将从字符串文字构造。右值变量已经可以绑定到这个,因为你已经传递了一个临时变量,左值变量可以绑定到临时变量,因为它是 const
.
这个例子,不会编译:
void write_Lvalue(const std::string &text) {
//...
}
void write_Rvalue(const std::string &&text) {
//...
}
int main() {
std::string a = "hello";
write_Rvalue(a);
}
因为我们试图将左值 a
传递给只接受右值的函数。
右值类型的好处是它们可以被移动。关于为什么移动可以更快 here。
有一个很好的 post使你的右值 const
违背了它的目的,尽管如评论中所述,因为它不能再移动了。
首先,常量右值引用并不是很有用,因为你不能移动它们。移动值需要可变引用才能工作。
让我们举个更正后的例子:
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");
}
在这种情况下,两者完全等价。在这两种情况下,编译器必须创建一个字符串并通过引用发送它:
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"});
}
那么为什么要有接受右值引用的函数呢?
这取决于您对字符串的处理方式。可以从以下位置移动可变引用:
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);
}
那么为什么要使用右值引用呢?为什么不使用可变左值引用?
那是因为可变左值引用不能绑定到临时对象:
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
}
但是可变右值引用可以绑定到右值,如上所示。