lvalues and rvalues

本文深入探讨了C++中的值类别概念,包括lvalue、rvalue及其引用的区别与用法,介绍了移动语义和完美转发等高级特性,并通过实例说明了如何在实践中正确运用这些概念。

参考链接:https://msdn.microsoft.com/en-us/library/f90831hc.aspx

  1. C++的任何表达式都是lvalue或者rvalue。lvalue指的是 在表达式之外依然一致的object,可以认为拥有名字的object都是lvalue,所以所有的变量都是lvalue。rvalue指的是 临时的值,在表达式之外使用就无法保证一致。

    // lvalues_and_rvalues.cpp  
    int main()  
    {  
    int i, j, *p;  
    
    // Correct usage: the variable i is an lvalue.  
    i = 7;  
    
    // Incorrect usage: The left operand must be an lvalue (C2106).  
    7 = i; // C2106  
    j * 4 = 7; // C2106, 如果重载乘号返回的是一个左值,这里也可以是正确的
    
    // Correct usage: the dereferenced pointer is an lvalue.  
    *p = i;   
    
    const int ci = 7;  
    // Incorrect usage: the variable is a non-modifiable lvalue (C3892).  
    ci = 9; // C3892  
    
    // Correct usage: the conditional operator returns an lvalue.  
    ((i < 3) ? i : j) = 7;  
    }  

    ​ 欲详细了解rvalue、lvalue、xvalue、glvalue、prvalue 见stackoverflow

  2. lvalue reference:可以认为左值引用就是另一个object的别名。用法为type-id & cast-expression

  3. rvalue reference:用法为type-id && cast-expression

    • move semantics

      右值引用是一个作用为了支持move semantics :允许无法引用的临时对象资源被传递。(move senmatics的实现可以参照这里。)一个例子是string的operator+。在VC++ 2010以前,operator+并不能用于直接将两个string相加。因为如果两个string都是lvalue,则很有可能在其他地方被引用了,因此不能更改它们。而rvalue不能在程序其它地方引用,operator+就不用害怕意外改变了其它地方的值,因此可以将两个string相加。同样还有vector溢出处理的问题可以帮助理解,详细看这里

    int main()  
    {  
      string s = string("h") + "e" + "ll" + "o";  
      cout << s << endl;  
    }  
    • perfect forwarding

      这里的forward的意思是一个泛型函数(比如模板函数)参数是引用参数,并将这些参数传递(forward)给其它函数。比如泛函数参数类型为const T&,则被调用的函数不能修改参数值。(而lvalue是允许修改的 )如果类型是T&,则函数不能传入rvalue调用(因为rvalue不能在其他修改,而T&允许修改参数 )。

      ​ 比如针对如下类,要写一个调用他们的泛函数。

      struct W  
      {  
      W(int&, int&) {}  
      };  
      
      struct X  
      {  
      X(const int&, int&) {}  
      };  
      
      struct Y  
      {  
      Y(int&, const int&) {}  
      };  
      
      struct Z  
      {  
      Z(const int&, const int&) {}  
      };  
      

      这是一个版本,但他只能调用左值,也就是允许在其他地方修改的值,要想代码正确需要一一实现对应的重载函数。

      template <typename T, typename A1, typename A2>  
      T* factory(A1& a1, A2& a2)  
      {  
      return new T(a1, a2);  
      }  
      int a = 4, b = 5;  
      W* pw = factory<W>(a, b);  
      Z* pz = factory<Z>(2, 2); // ERROR, rvalue, factory can only take lvalue reference

      而rvalue reference允许只用下面一个泛函数解决问题:

      template <typename T, typename A1, typename A2>  
      T* factory(A1&& a1, A2&& a2)  
      {  
      return new T(std::forward<A1>(a1), std::forward<A2>(a2));  
      }  // std::forward的作用是将factory函数的参数传给模板类的构造函数
      int main()  
      {  
      int a = 4, b = 5;  
      W* pw = factory<W>(a, b);  
      X* px = factory<X>(2, b);  
      Y* py = factory<Y>(a, 2);  
      Z* pz = factory<Z>(2, 2);  
      }  

      允许facotry同时进行lvalue和rvalue调用的原因是由于reference collapsing rule的存在,可以对推测参数类型。

      Template argument deduction is an important element of implementing perfect forwarding.

      collapsing rule :

    Expanded typeCollapsed type
    T& &T&
    T& &&T&
    T&& &T&&
    T&& &&T&&

    比如以下例子:

    c++
    template<typename T>
    void foo(T&&);

    1. 当foo传进参数A类型是lvalue, 则编译器将T推测为A&, 根据collapsing rule, A& &&就是A&。
    2. foo传进参数A类型是rvalue, 则T被推测为A, 因此A&&就是A&&。

      更详细的,可参考stackoverflow上的解释

      还是没非常理解,需要多看看相关知识。。@_@

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) ~\AppData\Local\Temp\ipykernel_21072\1850121073.py in <module> 1 # 将X1列转换为布尔值(True/False),再转为整数(1/0) ----> 2 df['X1_bool'] = (df['X1'] > threshold).astype(int) # 替换实际阈值 D:\anaconda\lib\site-packages\pandas\core\ops\common.py in new_method(self, other) 68 other = item_from_zerodim(other) 69 ---> 70 return method(self, other) 71 72 return new_method D:\anaconda\lib\site-packages\pandas\core\arraylike.py in __gt__(self, other) 54 @unpack_zerodim_and_defer("__gt__") 55 def __gt__(self, other): ---> 56 return self._cmp_method(other, operator.gt) 57 58 @unpack_zerodim_and_defer("__ge__") D:\anaconda\lib\site-packages\pandas\core\series.py in _cmp_method(self, other, op) 5621 5622 with np.errstate(all="ignore"): -> 5623 res_values = ops.comparison_op(lvalues, rvalues, op) 5624 5625 return self._construct_result(res_values, name=res_name) D:\anaconda\lib\site-packages\pandas\core\ops\array_ops.py in comparison_op(left, right, op) 281 282 elif is_object_dtype(lvalues.dtype) or isinstance(rvalues, str): --> 283 res_values = comp_method_OBJECT_ARRAY(op, lvalues, rvalues) 284 285 else: D:\anaconda\lib\site-packages\pandas\core\ops\array_ops.py in comp_method_OBJECT_ARRAY(op, x, y) 71 result = libops.vec_compare(x.ravel(), y.ravel(), op) 72 else: ---> 73 result = libops.scalar_compare(x.ravel(), y, op) 74 return result.reshape(x.shape) 75 D:\anaconda\lib\site-packages\pandas\_libs\ops.pyx in pandas._libs.ops.scalar_compare() TypeError: '<' not supported between instances of 'numpy.ndarray' and 'str'
07-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值