右值引用是 C++11 引入的与 Lambda 表达式齐名的重要特性之一。它的引入解决了 C++ 中大量的历史遗留问题,消除了诸如 std::vector、std::string 之类的额外开销,也才使得函数对象容器 std::function 成为了可能。
要弄明白右值引用到底是怎么一回事,必须要对左值和右值做一个明确的理解。
- 左值(lvalue, left value),顾名思义就是赋值符号左边的值。准确来说,左值是表达式(不一定是赋值表达式)后依然存在的持久对象。
-
右值(rvalue, right value),右边的值,是指表达式结束后就不再存在的临时对象。
而 C++11 中为了引入强大的右值引用,将右值的概念进行了进一步的划分,分为:纯右值、将亡值。 - 纯右值(prvalue, pure rvalue),纯粹的右值,要么是纯粹的字面量,例如 10, true;要么是求值结果相当于字面量或匿名临时对象,例如 1+2。非引用返回的临时变量、运算表达式产生的临时变量、原始字面量、Lambda 表达式都属于纯右值。
- 将亡值(xvalue, expiring value),是 C++11 为了引入右值引用而提出的概念(因此在传统 C++中,纯右值和右值是统一个概念),也就是即将被销毁、却能够被移动的值。
实例1
void process_value(int& i) {
std::cout << "LValue processed: " << i << std::endl;
}
void process_value(int&& i) {
std::cout << "RValue processed: " << i << std::endl;
}
int main() {
int a = 0;
process_value(a);
process_value(1);
}
运行结果
LValue processed: 0
RValue processed: 1
实例2
class MyString {
public:
MyString() {
std::cout << "MyString() called" << std::endl;
}
MyString(const MyString& rhs) {
std::cout << "MyString(const MyString& rhs) called" << std::endl;
}
MyString& operator=(const MyString& rhs) {
std::cout << "operator=(const MyString& rhs) called" << std::endl;
}
MyString(const MyString&& rhs) {
std::cout << "MyString(const MyString&& rhs) called" << std::endl;
}
MyString& operator=(const MyString&& rhs) {
std::cout << "operator=(const MyString&& rhs) called" << std::endl;
}
~MyString() {
std::cout << "~MyString() called" << std::endl;
}
};
int main() {
MyString mystr;
MyString mystr1;
mystr1 = mystr; // copy constructor called
MyString mystr2(mystr); // copy operator= called
mystr1 = std::move(mystr); // move constructor called
MyString mystr3(std::move(mystr)); // move operator= called
}
运行结果
MyString() called
MyString() called
operator=(const MyString& rhs) called
MyString(const MyString& rhs) called
operator=(const MyString&& rhs) called
MyString(const MyString&& rhs) called
~MyString() called
~MyString() called
~MyString() called
~MyString() called
网友评论