快捷搜索:  汽车  科技

c语言中的等号从左往右看(C基础篇左值引用)

c语言中的等号从左往右看(C基础篇左值引用)这其实就像计算机中拷贝文件,对文件的拷贝总是费时的且占用空间的,但移动文件却是便捷高效的。如果我们想把某个文件从同一个磁盘的A文件夹移动到B文件夹,如果我们复制文件、粘贴文件、删除A文件夹下原文件,这个操作是费时且低效的,移动他是最有效的办法--只是改变文件目录记录文件依然还在磁盘原来的位置。右值引用 (Rvalue Referene) 是 C 新标准 (C 11 11 代表 2011 年 ) 中引入的新特性。左值引用使标识符可以绑定左值,而右值引用可以绑定右值。int &ref_a = a;声明引用时需注意:引用与指针的差别

c语言中的等号从左往右看(C基础篇左值引用)(1)

什么是左值和右值?

左值是变量的地址,如变量名或指针。右值则是变量存储的内容。

int a=3; // a变量名,3是变量a存储的内容

当一个对象被用作左值的时候,用的是对象的身份,也就是在内存中的位置。而当对象被用作右值的时候,用的则是对象的值。左值是持久的,它存在于作用域期间。而右值是短暂的,它可以是字面常量或者是表达式产生的临时对象。

左值引用‘&’

左值引用本质上是一个隐式指针,为对象的一个别名。通常我们所说的‘引用’指的就是‘左值引用’。

int &ref_a = a;

声明引用时需注意:

  • 引用在声明时必须初始化。
  • 引用作为目标的别名使用,对引用的改动实际就是对目标的改动。
  • 引用和变量指向同一地址单元。

引用与指针的差别

  • 指针是个变量,可以把它再赋值指向别去的地址。
  • 建立引用时必须进行初始化,且不会再关联其他不同变量。
  • 因为指针是变量,所以可以有指针的引用。
右值引用‘&&’

右值引用 (Rvalue Referene) 是 C 新标准 (C 11 11 代表 2011 年 ) 中引入的新特性。左值引用使标识符可以绑定左值,而右值引用可以绑定右值。

  • 但是针对临时对象的右值引用究竟有什么存在的意义了?

这其实就像计算机中拷贝文件,对文件的拷贝总是费时的且占用空间的,但移动文件却是便捷高效的。如果我们想把某个文件从同一个磁盘的A文件夹移动到B文件夹,如果我们复制文件、粘贴文件、删除A文件夹下原文件,这个操作是费时且低效的,移动他是最有效的办法--只是改变文件目录记录文件依然还在磁盘原来的位置。


接下来我们通过移动语义示例来深入解析右值引用

移动语义-移动构造函数和移动赋值运算符

移动语义避免了移动原始数据,而只是修改了记录。这相当于计算机中移动文件,实际文件还留在原来的位置,而只是修改了记录。

实现移动语义:定义两个构造函数。一个是使用const左值引用作为参数的拷贝构造函数—可以实现深拷贝。一个是使用右值引用作为参数,它只在函数内实现所有权的转移—类似浅拷贝,但需要将指针成员指向NULL,而这是修改,因此不能为const。

下面是个示例:

我们可以从示例代码中可以看到,移动构造函数和移动赋值函数实现的功能都是将传入的右值临时对象申请的内存的所有权转让给创建的新对象或者是被赋值对象,而原临时对象指向nullpter。

c语言中的等号从左往右看(C基础篇左值引用)(2)

obj类: 默认构造函数、拷贝构造函数、移动构造函数

c语言中的等号从左往右看(C基础篇左值引用)(3)

重载双目 运算符和移动赋值运算符

obj o1 = (1 "abc"); // 调用 constructor

obj o2(o1); // 调用 copy constructor

移动构造在GNU和VS下的区别

obj o3(o1 o2); // GNU下 constructor、operator

obj o3(o1 o2); // VS 下 constructor创建临时对象,再 move constructor 创建对象o3

o1 o2的结果是一个临时对象,是右值。通常认为上面的语句是必然会调用移动构造函数的,但真的是吗?

  • GNU编译器优化不会调用移动构造函数

这对如上语句,在GNU G 编译器下会进行优化,认为o3是 的受益人,它会将双目运算 返回的临时变量tmp直接转移给o3,因此这个过程在GNU G 中是不会调用移动构造函数。

  • VS编译器则会调用移动构造函数

步骤是先执行operator ,在执行过程中调用constructor构建临时对象tmp。然后tmp被当做右值通过移动构造函数将tmp申请的内存对象转移给了o3,同时析构临时对象tmp(内存已被转移给了o3,tmp._name=nullptr)。

猜您喜欢: