c++_左值引用, 右值引用, std::move

catalogOverview左右值引用右值引用、MoveOverview' “左值” 又称为 “左值表达式“, 两者一个东西。 '' 左值,其结果是一个“地址”,其操作 必须是一个“对象、内存” 有内存地址的东西'' 左值是一个地址,左值表达式的结果 得到的就是个对象 得有地址。'' 否则,与左值相对应的 便是右值。 (两者不可能同时兼具)'=== 要么是左值,要么是右值!!! (因为对于左值,可能他也会具备 右值的性质) ===== 但具备右值的“性质”,并不是说 他是右值!! ==/
摘要由CSDN通过智能技术生成

is_lvalue_reference

using T = QString;
using TT = T &;
using TTT = T &&;
using A = QString *;
using AA = A &;
using AAA = A &&;
DE<< ::std::is_lvalue_reference< T>::value << ", " << ::std::is_rvalue_reference< T>::value;
DE<< ::std::is_lvalue_reference< TT>::value << ", " << ::std::is_rvalue_reference< TT>::value;
DE<< ::std::is_lvalue_reference< TTT>::value << ", " << ::std::is_rvalue_reference< TTT>::value;
DE<< ::std::is_lvalue_reference< A>::value << ", " << ::std::is_rvalue_reference< A>::value;
DE<< ::std::is_lvalue_reference< AA>::value << ", " << ::std::is_rvalue_reference< AA>::value;
DE<< ::std::is_lvalue_reference< AAA>::value << ", " << ::std::is_rvalue_reference< AAA>::value;

false ,  false
true ,  false
false ,  true
false ,  false
true ,  false
false ,  true

右值引用作为函数参数

一个临时对象Foo(), 会优先进入 [const] Foo &&, 而其次才是 const Foo &

如果, 既有Foo 又有[const] Foo &&, 两个重载; 此时, Foo()临时对象 同时满足两个 ==此时会报错的!!! ambiguous ==

即重载函数, [const] T &&T, 只能选择1个


最标准的写法是:
一个是左值引用: const T &, 一个是右值引用T &&

我们知道, 一般一个类, 会有: (左值拷贝构造) 和 (右值拷贝构造), 他的最标准写法是:

class Foo{
   
	Foo( const Foo &){
   }
	Foo( Foo &&){
   }
}

下面解释下, 为什么是&&, 而不是const &&
func( T && _t)
此时的这个_t, 一定是一个临时对象; 什么叫"临时对象"呢??? 外界一定不会(访问/修改)这个临时对象!!
因为, 这个临时对象, 他是匿名的; 外界根本获取不到这个临时对象;
既然外界不会用到这个对象, 那么, 不写const; 此时, 在这个函数里 就可以直接使用(修改)他


临时对象 与 右值

&Foo();
&(Foo().data);
Foo().data = 123;

以上这3个操作, 都是非法的; 因为, 对一个右值 进行 左值操作, 是不允许的!!!


此时引入(右值引用), 他有2个功能:

  • 右值引用, 可以延长 右值(临时对象)的生命期;
    本来临时对象现在马上就要摧毁, 现在有个 (右值引用) 引用上他, 这个临时对象的生命期, 就和这个 (右值引用) 一样的
  • 右值引用, 本身是(左值); 即, 右值引用 可以进行 (左值操作)
    即, 右值引用给了我们一个渠道, 我们可以 使用 左值操作 来操作一个 临时对象!!
    void func( Foo && f){
           ' 这个f, 就是那个Foo()临时对象, 两个是同一个对象 '
    	&f;  ' 获取 临时对象的地址 '
    	&(f.data);    ' 成员变量地址 '
    	f.data = 123;  ' 成员变量赋值 '
    }
    
    int main(){
         
    	func( Foo());
    }
    
    全程, 只会产生1个对象

引用/指针的隐患

引用传参

class Foo{
   
	const T * ref;
	void func( [const] T & _o){
   
		ref = &_o;
	}
}

虽然这个ref成员变量, 是const的; 但, 这依然是危险的!!!

因为外界在调用func时: func( obj), 这个T obj的生命周期 可能会早于 Foo对象的生命!!!
导致, T obj已经销毁了, 而ref里还存着他的地址!!! 非常危险

你必须要自己保证: ref的生命期 是早于 他所引用的对象!!!

返回值为引用

class Foo{
   
	T data;
	[const] T & get(){
    return data;}
};

当你[const] T * ref; ref = &( foo.get());时, 问题和上面是类似的
你的foo生命期, 可能是 早于 ref的; 此时: ref里 存了一个 已经销毁的对象; 这当然是危险的

一个处理办法是: 不要使用(指针)
如果你使用: [const] T & ref = foo.get();, 由于引用必须初始化; 所以, ref的生命期 一定早于 foo

但是, 你无法控制(用户)…
总之, 你返回一个[const]引用, 就是有隐患的, c++并不推荐这样错!!!

偶尔, 可以使用; 但你必须要, 自己确保 安全性!!!

比如, stl的operator[]就是返回的 [const]引用; 但这并不是常态;


补充
即使你使用引用, 还是有隐患!!!

class ST{
   
public:
    string str;
    string & get(){
    return str;}
};

当你使用: string & ref = ST().get();时, 此时, 引用再一次指向了: 已经delete了的内存!!!

这是隐蔽的 危险的 bug…

当你使用: T & ref = AA.BB.CC.get()时, 不能只看get() 返回的是T &, 就以为 万事如意了
你还必须要保证: AA, BB, CC都是引用, 绝不会产生临时对象!!!

引用是右值

void func( int && _d0){
   
}

{
   
	int a = 123;
	func( ?);
}

func( 123) 是可以的 123是常量, 右值
func( a) 是错误的!!! a是左值; 右值绑定_d0 不可以绑定到 左值上

但是

using Type = int &;
void func( Type && _d0){
   
}

{
   
	int a = 123;
	func( 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值