标签:定义 temp 资源 引用 赋值 reference 函数返回 col c++
首先要分清:
C++里的值只有两种值:左值、右值。—— 其本质应该是内存中存储的值/instance分两种:一种是持久的,一种是“短暂的”
也只有两种引用: 左值引用、右值引用。 ——引用,就是这个内存地址的助记符(别名)。
1. 左值引用 需绑定、也只能绑定 左值。
同理,右值引用 需绑定、也只能绑定 右值。
2. 有两种特别的引用既可以绑定左值、又可以绑定右值。分别是:
①const T&
② universal reference : “T&& t在发生自动类型推断的时候,它是未定的引用类型”—— 指的是template的推断/ auto推断
3. int&& t = getTemp(); 则“getTemp()”是右值
但用t绑定该右值后,该右值的生命周期就被延长(和t的生命周期一样)。
注意,此时t已经是持久的值,而且可以对其取地址的。(赋值也没编译报错~)
★ 此时: ① t是右值引用 ② t是一个左值 “绑定了右值的右值引用本身 是一个左值” 【这符合 “ 左值持久、右值短暂”】
再看函数调用:
传参的实质是把实参传递给形参。 其实质的过程却可以细分一下!
实参 ——> 形参
第1种: 值 ——> 引用
【左值】 int i = 1; foo(int& m); ——> foo(i); 则“传参” 是用形参的引用 绑定实参这个值。(是引用去绑定值的过程)
【右值】 T GetTemp(); foo(T&& m); ——> foo( GetTemp() ); (此时在函数内 可以 move(m) 后 接管这个右值的临时资源了)
第2种: 值 ——> 值
【左值】 int t = 1; foo(int p); ——> foo(t); 则“传参”是用 t 拷贝值给 p。 (值拷贝) —— 前提同下。可通过move(lvalue) 将左值转换为右值,以进行移动
【右值】 T GetTemp(); foo(T m); ——> foo( GetTemp() ); (值移动) ——前提: 该类型已定义了 const T&的拷贝构造 、 T&&的移动构造
第3种: 引用 ——> 值
【左值(引用) —> 左值】 int i =1; int& t = i; foo(int m); ——> foo(t); ★ 对于左值来说,使用左值、左值引用 在传递时 没有区别。都是指 那个持久的值。 相当于第2种“左值——>左值”
【右值引用(左值)——> 左值】 T&& t = GetTemp(); foo(T m); ——> foo(t); 相当于第2种“左值——>左值” : m是临时对象“GetTemp()”的拷贝
第3种: 引用 ——> 引用
【左值(引用) —> 左值引用】 int i =1; int& t = i; foo(int& m); ——> foo(t); 则“传参”就相当于 int& ref2 = ref1;
【右值引用(左值)——> 左值引用/ const 左值引用 / universal reference】 T&& t = GetTemp(); foo(T&& m); ——> foo(t)无法匹配,“右值引用m 无法绑定 左值t”
T&& t = GetTemp(); foo(T& m); ——> foo( t);
函数返回时 T GetTemp() { return T();} 会发生 T() 这个右值到 “GetTemp()” 这个临时变量的移动。
那么, 函数调用传参时, 会发生实参到形参的移动吗 ???
肯定会,比如unique_ptr, iostream 这种只能移动的东西。
当然可以:和返回时一样,去 右值去适配 T的构造就行: GetTemp() ——> T , 即 foo(T t) ; 调用 foo(GetTemp())
完美转发(perfect forwarding)、universal reference
标签:定义 temp 资源 引用 赋值 reference 函数返回 col c++
原文地址:https://www.cnblogs.com/nanlan2017/p/9255319.html