设为首页 加入收藏

TOP

c++ 右值引用(一)
2019-09-30 16:41:36 】 浏览:89
Tags:引用

1. 左值和右值

  简单的定义来说,能够放在赋值等号左边的就是左值,反之则是右值(所有表达式不是左值就是右值,左右值不存在交集)——但是这个解释实在有点鸡肋。下面对定义结合例子做些补充。

  • 右值:在内存中不占有内存的表达式
  • 左值:在内存中占有一定内存位置的表达式
1 int i;
2 i = 2; //合法
3 2 = i; //非法

  例子合法性很好理解——可以在结合左右值的定义。

 1 #include<iostream>
 2 int main()
 3 {
 4     int t;
 5     int* q = &(t + 1);//非法,t+1在内存中没有位置
 6 
 7     int arr[] = { 1,2,3 }; int r[] = { 1,2,3 };
 8     int* i = arr; //合法
 9     std::cout << arr << std::endl; // 006FF808
10     arr = r; // 非法
11     *(arr) = 10;//合法
12 }

  在这里,我们需要理解下第八行,arr 作为右值—— 注意 arr 是内存地址,是一个地址,不同于第一个例子中的 i 。在第九行可以看到打印的 arr 代表的地址内容,第十行也就必定是错误的(是右值就不可能作为左值)。

  而第11行,arr 貌似变成了左值——也就是左值和右值在一定程度上是可以转换的。其中扮演关键角色的就是 * 解引用。既然是左值,按照我们前面说的,那应该在内存中存在一处分配的内存位置,*arr 解引用之后的确是存了 1 这个数,所以可以重新赋值10。

 

2. 右值引用

  通过下面的例子来理解:

 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 struct A
 5 {
 6     // 构造函数
 7     explicit A(size_t _size = 0) :size(_size),ptr(new int[_size]()) {
 8         cout << "construct..."<< endl;
 9     }
10 
11     // 拷贝赋值运算符
12     A& operator=(const A& tmp) {
13         if (&tmp != this)
14         {
15             this->ptr = new int[tmp.size];
16             for (size_t i = 0; i < tmp.size; ++i) {
17                 this->ptr[i] = tmp.ptr[i];
18             }
19         }
20         cout << "copy assignment 等于..." << endl;
21         return *this;
22     }
23 
24     // 拷贝构造函数
25      A(const A& tmp) {
26         this->ptr = new int[tmp.size];
27         for (size_t i = 0; i < tmp.size; ++i) {
28             this->ptr[i] = tmp.ptr[i];
29         }
30         cout << "copy construct..." << endl;
31     }
32 
33     // 析构函数
34     ~A() {
35         if (ptr) 
36         {
37             delete[] ptr;
38             size = 0;
39             cout << "destructor..." << endl;
40         }
41     }
42 
43 private:
44     int* ptr;
45     size_t size;
46 };
47 
48 int main()
49 {
50     A a(10);
51     A b;
52 
53     cout<< "=====start=====" <<endl;
54     b = a;
55     cout << "=====end=====" << endl << endl;
56 
57     cout << "=====start2=====" << endl;
58     A c = a;//是拷贝构造。或者加上explicit改成A c(a) 可能更好理解
59     cout << "=====end2=====" << endl << endl;
60 
61     A d;
62     cout << "=====start3=====" << endl;
63     d = A(5);
64     cout << "=====end3=====" << endl << endl;
65 
66     return 0;
67 }

 

 

   结果上看,应该都比较好理解。

  其中第三处是要引出的重点,可以看到应该使用了 d = A(10),这条语句,A() 是一个临时变量,在完成 construct -> copy assignment 之后就进行了 destructor。我们来讨论下这一句赋值语句的内部过程,A(10) 调用构造函数并申请了内存空间,然后去实现拷贝赋值运算符,临时变量A(10)的内容【copy】给 d 变量,随后 A(10) 被销毁。而我们知道在 copy assignment (拷贝赋值运算符)方法中,我们又为 d 变量同样申请了 大小为10的数组空间,这就出现了一定的“低效处理”。不妨这样想,如果我们将A(10)申请的空间,通过拷贝赋值运算符,直接将这个空间给变量d,这样d就不用再去申请空间(反正A(10)的空间申请了,马上就会释放。相当于白白多申请和释放了一次,不如直接将A(10)的空间转移到d变量名下)。

  这就引入了右值引用,如下例子:

 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 struct A
 5 {
 6     // 构造函数
 7     explicit A(size_t _size = 0) :size(_size),ptr(new int[_size]()) {
 8         cout << "construct..."<< endl;
 9     }
10 
11     // 拷贝赋值运算符
12     A& operator=(const A& tmp) {
13         if (&tmp != this)
14         {
15             this->ptr = new int[tmp.size];
16             for (size_t i = 0; i < tmp.size; ++i) {
17                 this->ptr[i] = tmp.ptr[i];
18             }
19         }
20         cout << "copy assignment 等于..." << endl;
21         return *this;
22     }
23 
24     // 使用右值引用的拷贝赋值运算符
25     A& operator=(A&
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇cf-786B区间图最短路 下一篇C++—lambda表达式+优先队列 pror..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目