表达式左值右值(C++学习)
来源:互联网 发布:淘宝网制作费用 编辑:程序博客网 时间:2024/06/05 01:14
左值右值是表达式的属性,该属性称为 value category。按该属性分类,每一个表达式属于下列之一:
lvalue
left value,传统意义上的左值
xvalue
expiring value, x值,指通过“右值引用”产生的对象
prvalue
pure rvalue,纯右值,传统意义上的右值(?)
而 xvalue 和其他两个类型分别复合,构成:
lvalue + xvalue = glvalue
general lvalue,泛左值
xvalue + prvalue = rvalue
右值
区分?
++x 与 x++ 假定x的定义为 int x=0;,那么前者是 lvalue,后者是rvalue。前者修改自身值,并返回自身;后者先创建一个临时对像,为其赋值,而后修改x的值,最后返回临时对像。
区分表达式的左右值属性有一个简便方法:若可对表达式用 & 符取址,则为左值,否则为右值。比如
&obj , &*ptr , &ptr[index] , &++x
有效
&1729 , &(x + y) , &std::string("meow"), &x++
无效
对于函数调用,根绝返回值类型不同,可以是lvalue、xvalue、prvalue:
The result of calling a function whose return type is an lvalue reference is an lvalue
The result of calling a function whose return type is an rvalue reference is an xvalue.
The result of calling a function whose return type is not a reference is a prvalue.
const vs non-const
左值和右值表达式都可以是const或non-const。
比如,变量和函数的定义为:
string one("lvalue");const string two("clvalue");string three() { return "rvalue"; }const string four() { return "crvalue"; }
那么表达式:
表达式
分类
one
modifiable lvalue
two
const lvalue
three()
modifiable rvalue
four()
const rvalue
引用
Type&
只能绑定到可修改的左值表达式
const Type&
可以绑定到任何表达式
Type&&
可绑定到可修改的左值或右值表达式
const Type&&
可以绑定到任何表达式
重载函数
#include <iostream>#include <string>using namespace std;string one("lvalue");const string two("clvalue");string three() { return "rvalue"; }const string four() { return "crvalue"; }void func(string& s){ cout << "func(string& s): " << s << endl;}void func(const string& s){ cout << "func(const string& s): " << s << endl;}void func(string&& s){ cout << "func(string&& s): " << s << endl;}void func(const string&& s){ cout << "func(const string&& s): " << s << endl;}int main(){ func(one); func(two); func(three()); func(four()); return 0;}
结果:
func(string& s): lvaluefunc(const string& s): clvaluefunc(string&& s): rvaluefunc(const string&& s): crvalue
如果只保留const string& 和 string&& 两个重载函数,结果为:
func(const string& s): lvaluefunc(const string& s): clvaluefunc(string&& s): rvaluefunc(const string& s): crvalue
右值引用
C++0x第5章的第6段:
Named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not.
- 具名右值引用被视为左值
- 无名对对象的右值引用被视为x值
- 对函数的右值引用无论具名与否都将被视为左值
#include <iostream>#include <string>void F1(int&& a){ std::cout<<"F1(int&&) "<<a<<std::endl;}void F1(const int& a){ std::cout<<"F1(const int&) "<<a<<std::endl;}void F2(int&& a){ F1(a);}int main(){ int && a=1; F2(a); F1(a); F2(2); F1(2); return 0;}
结果
F1(const int&) 1F1(const int&) 1F1(const int&) 2F1(int&&) 2
移动语义
在这之前,如果写一个交换两个值的swap函数:
template <class T> swap(T& a, T& b){ T tmp(a); // now we have two copies of a a = b; // now we have two copies of b b = tmp; // now we have two copies of tmp (aka a)}
之后
template <class T> swap(T& a, T& b){ T tmp(std::move(a)); a = std::move(b); b = std::move(tmp);}
std::move 接受左值或右值参数,并返回一个右值(其所作工作很简单)
template <class T>typename remove_reference<T>::type&&move(T&& a){ return a;}
要是的swap真正发挥作用,需要重载:
class T{public: T(T&& ); T& operator = (T&& );...
模板参数类型
为了对比左值引用和右值引用,一开始误打误撞,写了这样一个函数
template <typename Type> void Swap(Type&& sb1, Type&& sb2){ Type sb(sb1); sb1 = sb2; sb2 = sb;}
然后
int main(){ int a=1, b=2; Swap(a, b); std::cout<<a<<" "<<b<<std::endl; return 0;}
结果却是
2 2
不用整数,换用一个自定义的类型试试看:
class A {public: A() { std::cout << "Default constructor." << std::endl; m_p = NULL; } ~A() { std::cout << "Destructor." << std::endl; delete m_p; } explicit A(const int n) { std::cout << "Unary constructor." << std::endl; m_p = new int(n); } A(const A& other) { std::cout << "Copy constructor." << std::endl; if (other.m_p) { m_p = new int(*other.m_p); } else { m_p = NULL; } } A(A&& other) { std::cout << "Move constructor." << std::endl; m_p = other.m_p; other.m_p = NULL; } A& operator=(const A& other) { std::cout << "Copy assignment operator." << std::endl; if (this != &other) { delete m_p; if (other.m_p) { m_p = new int(*other.m_p); } else { m_p = NULL; } } return *this; } A& operator=(A&& other) { std::cout << "Move assignment operator." << std::endl; if (this != &other) { delete m_p; m_p = other.m_p; other.m_p = NULL; } return *this; } int get() const { return m_p ? *m_p : 0; }private: int * m_p;};int main(){ A a(1); A b(2); Swap2(a, b); std::cout<<a.get()<<" "<<b.get()<<std::endl; return 0;}
结果
Unary constructor.Unary constructor.Copy assignment operator.Copy assignment operator.2 2Destructor.Destructor.
只出现了两个对象,那么Swap中的临时对象去哪儿了?
C++0x 14.8.2.1
If P is a cv-qualified type, the top level cv-qualifiers of P’s type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction. If P is an rvalue reference to a cv unqualified template parameter and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction. template <class T> int f(T&&);template <class T> int g(const T&&);int i;int n1 = f(i); // calls f<int&>(int&)int n2 = f(0); // calls f<int>(int&&)int n3 = g(i); // error: would call g<int>(const int&&), which// would bind an rvalue reference to an lvalue
也就是前面提到的
template <typename Type> void Swap(Type&& sb1, Type&& sb2)
参数推导后
void Swap<int&>(int& sb1, int& sb1)
参考
http://blog.csdn.net/zwvista/article/details/5459774
http://blog.csdn.net/hikaliv/article/details/4541429
http://topic.csdn.net/u/20090706/16/514af7e1-ad20-4ea3-bdf0-bfe6d34d9814.html
http://www.artima.com/cppsource/rvalue.html
- c语言学习1.2表达式
- linux c一站式学习 表达式
- 数据结构学习---中缀表达式转后缀表达式(c++)
- c++Primer学习笔记(4)--表达式
- 正则表达式使用学习(C++、Qt、Python)
- c++primer学习笔记(5.0)表达式
- 【C语言】正则表达式学习笔记
- C sharp 泛型 lambda表达式学习笔记
- C++Primer学习笔记5 表达式
- 学习C++——lambda表达式
- c语言学习篇--逗号表达式
- C++11 学习笔记 lambda表达式
- 我的c学习:逻辑表达式
- c语言学习----运算符与表达式
- C++primer学习笔记-第五章表达式
- C#Regex正则表达式学习笔记
- 学习C++——lambda表达式
- C语言表达式 ——学习笔记
- Android完全退出应用程序的三种方法(转载)
- 冒泡排序
- 2011-8-6
- 2011.08.06
- java中的集合类 以及 迭代器
- 表达式左值右值(C++学习)
- 刚刚CSDN号发现密码被改了 ...幸好找回来了。。
- the CComObjectRootEx
- poj1269
- tiny6410 Linux启动信息
- Phyx3@CGDC4
- 【教程】Gentoo的安装
- linux 内核中的锁机制--RCU
- android2.2