在c++98中,变量分为左值和右值,左值指的是可以取地址的变量,右值指的是非左值。二者的根本区别在于能否获取内存地址,能否赋值不是区分的依据。
四个变量或者表达式:
string one("one"); const string two("two"); string three() { return "three"; } const string four() { return "four"; }
其中,前两个为左值,后两个为右值。
C++98中的引用分为两种“const引用”和“非const引用”,其中const引用,可以引用所有的变量。而后者只能引用非const左值,即one。
这四个变量,只有one可以接受修改语义,其余三个只能接受常亮语义。
以string为例,const string &,可以接受认可形式的参数,包括"foo",string("bar"),但是string &只能接受一个string s;之类的参数,可以从语义的角度来看,string &是一种修改引用。
下面提供一段测试代码:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 6 string one("one"); 7 const string two("two"); 8 string three() { return "three"; } 9 const string four() { return "four"; } 10 11 void test(const string &s) 12 { 13 cout << "test(const string &s):" << s << endl; 14 } 15 16 void test(string &s) 17 { 18 cout << "test(string &s):" << s << endl; 19 } 20 21 22 int main(int argc, char const *argv[]) 23 { 24 25 26 test(one); 27 test(two); 28 test(three()); 29 test(four()); 30 31 32 return 0; 33 }
测试结果如下:
test(string &s):one test(const string &s):two test(const string &s):three test(const string &s):four
从测试结果可知:
如果同时提供const引用和非const引用版本的重载,那么one会优先选择更加符合自身的非const引用。其他三个变量只能选择const引用.
从测试结果中,反应出C++重载决议的一个特点:参数在通用参数和更加符合自身的参数之间,优先选择后者。
注意:引用不是数据类型,而是一种属性。
四个变量或者表达式:
string one("foo"); 非const左值 const string two("bar"); const左值 string three() { return "three"; } 非const右值 const string four() { return "four"; } const右值
参数接收情况:
const X&可以接受所有的参数。 X&只可以接收非const左值。 X&&只可以接收非const右值。 const X&&可以接受右值。
只有X&&类型的变量可以被移动(move)
在C++11中,一个类应该提供的构造函数有:
a) Test();
b) Test(const Test &)拷贝构造函数
c) Test(Test &&) 移动构造函数
一个类应该提供的赋值操作符有:
a) Test &operator=(const Test &);
b) Test &operator=(Test &&); 移动赋值运算符
std::move的作用是将一个变量强制转化为右值引用。move会导致原来的变量失效。
(const string &name)和(string &&name)可以合并为(string name),但是后者需要显式的调用move函数。
右值引用带来的变化主要是:移动语义(move semantics)、完美转发(perfect forward)。