C++中的左值和右值

左值和右值的定义

在C++中,可以放到赋值操作符=左边的是左值,可以放到赋值操作符右边的是右值。有些变量既可以当左值又可以当右值。进一步来讲,左值为Lvalue,其实L代表Location,表示在内存中可以寻址,可以给它赋值(常量const类型也可以寻址,但是不能赋值),Rvalue中的R代表Read,就是可以知道它的值。例如:
int a=3;
a在内存中有地址,而3没有,但是可以read到它的值。
3=4;
这个是错误的,因为3的内存中没有地址,不能当作左值。
下面这个语句不容易出错
a++=3;
这个语句编译通不过的,原因在于a++是先使用a的值,再给a加1。实现如下:
  1. {  
  2.     int tmp=a;  
  3.     a=a+1;  
  4.     return tmp;  
  5. }  
{
    int tmp=a;
    a=a+1;
    return tmp;
}
++a是右值。
++a=3;
这个是正确的,++a的实现如下:
  1. {  
  2.     a=a+1;  
  3.     return &a;  
  4. }  
{
    a=a+1;
    return &a;
}
显然++a的效率高。

左值符号&和右值符号&&

左值的声明符号为&,右值的声明符号为&&。在C++中,临时对象不能作为左值,但是可以作为常量引用const &
  1. #include<iostream>  
  2. void print_lvalue(int& i)//左值  
  3. {  
  4.     std::cout << ”Lvalue:” << i << std::endl;  
  5. }  
  6. void print_rvalue(int&& i)//右值  
  7. {  
  8.     std::cout << ”Rvalue:” << i << std::endl;  
  9. }  
  10.   
  11. int main()  
  12. {  
  13.     int i = 0;  
  14.     print_lvalue(i);  
  15.     print_rvalue(1);  
  16.     //print_lvalue(1)会出错  
  17.     //print_lvalue(const int& i)可以使用print_lvalue(1)  
  18.     return 0;  
  19. }  
#include<iostream>
void print_lvalue(int& i)//左值
{
    std::cout << "Lvalue:" << i << std::endl;
}
void print_rvalue(int&& i)//右值
{
    std::cout << "Rvalue:" << i << std::endl;
}

int main()
{
    int i = 0;
    print_lvalue(i);
    print_rvalue(1);
    //print_lvalue(1)会出错
    //print_lvalue(const int& i)可以使用print_lvalue(1)
    return 0;
}

C++11中的move

有时候我们希望把左值当作右值来使用,例如一个变量的值,不再使用了,希望把它的值转移出去,C++11中的std::move就为我们提供了将左值引用转为右值引用的方法。
  1. #include<iostream>  
  2. void print_value(int& i)//左值  
  3. {  
  4.     std::cout << ”Lvalue:” << i << std::endl;  
  5. }  
  6. void print_value(int&& i)//右值  
  7. {  
  8.     std::cout << ”Rvalue:” << i << std::endl;  
  9. }  
  10.   
  11. int main()  
  12. {  
  13.     int i = 10;  
  14.     print_value(i);  
  15.     print_value(std::move(i));  
  16.     return 0;  
  17. }  
#include<iostream>
void print_value(int& i)//左值
{
    std::cout << "Lvalue:" << i << std::endl;
}
void print_value(int&& i)//右值
{
    std::cout << "Rvalue:" << i << std::endl;
}

int main()
{
    int i = 10;
    print_value(i);
    print_value(std::move(i));
    return 0;
}

最长用的交换函数
  1. void swap(T& a, T& b)  
  2. {  
  3.     T tmp = std::move(a);  
  4.     a = std::move(b);  
  5.     b = std::move(tmp);  
  6. }  
void swap(T& a, T& b)
{
    T tmp = std::move(a);
    a = std::move(b);
    b = std::move(tmp);
}
避免了3次拷贝。

move的本质,只是将参数转换为右值引用,并没有移动什么。因此要实现类关于右值得构造函数和复制操作符。move实现如下:
  1. template <typename T>  
  2. decltype (auto) move(T&& param){  
  3.     using ReturnType = remove_reference_t<T>&&;  
  4.     return static_cast<ReturnType>(param);  
  5. }  
template <typename T>
decltype (auto) move(T&& param){
    using ReturnType = remove_reference_t<T>&&;
    return static_cast<ReturnType>(param);
}


精确值传递

std::forward主要用于模板编程中,值传递的问题。可以推测参数是左值引用还是右值引用,精确传递值。参考这里:
http://blog.csdn.net/zwvista/article/details/6848582

左值和右值的定义

在C++中,可以放到赋值操作符=左边的是左值,可以放到赋值操作符右边的是右值。有些变量既可以当左值又可以当右值。进一步来讲,左值为Lvalue,其实L代表Location,表示在内存中可以寻址,可以给它赋值(常量const类型也可以寻址,但是不能赋值),Rvalue中的R代表Read,就是可以知道它的值。例如:
int a=3;
a在内存中有地址,而3没有,但是可以read到它的值。
3=4;
这个是错误的,因为3的内存中没有地址,不能当作左值。
下面这个语句不容易出错
a++=3;
这个语句编译通不过的,原因在于a++是先使用a的值,再给a加1。实现如下:
  1. {  
  2.     int tmp=a;  
  3.     a=a+1;  
  4.     return tmp;  
  5. }  
{
    int tmp=a;
    a=a+1;
    return tmp;
}
++a是右值。
++a=3;
这个是正确的,++a的实现如下:
  1. {  
  2.     a=a+1;  
  3.     return &a;  
  4. }  
{
    a=a+1;
    return &a;
}
显然++a的效率高。

左值符号&和右值符号&&

左值的声明符号为&,右值的声明符号为&&。在C++中,临时对象不能作为左值,但是可以作为常量引用const &
  1. #include<iostream>  
  2. void print_lvalue(int& i)//左值  
  3. {  
  4.     std::cout << ”Lvalue:” << i << std::endl;  
  5. }  
  6. void print_rvalue(int&& i)//右值  
  7. {  
  8.     std::cout << ”Rvalue:” << i << std::endl;  
  9. }  
  10.   
  11. int main()  
  12. {  
  13.     int i = 0;  
  14.     print_lvalue(i);  
  15.     print_rvalue(1);  
  16.     //print_lvalue(1)会出错  
  17.     //print_lvalue(const int& i)可以使用print_lvalue(1)  
  18.     return 0;  
  19. }  
#include<iostream>
void print_lvalue(int& i)//左值
{
    std::cout << "Lvalue:" << i << std::endl;
}
void print_rvalue(int&& i)//右值
{
    std::cout << "Rvalue:" << i << std::endl;
}

int main()
{
    int i = 0;
    print_lvalue(i);
    print_rvalue(1);
    //print_lvalue(1)会出错
    //print_lvalue(const int& i)可以使用print_lvalue(1)
    return 0;
}

C++11中的move

有时候我们希望把左值当作右值来使用,例如一个变量的值,不再使用了,希望把它的值转移出去,C++11中的std::move就为我们提供了将左值引用转为右值引用的方法。
  1. #include<iostream>  
  2. void print_value(int& i)//左值  
  3. {  
  4.     std::cout << ”Lvalue:” << i << std::endl;  
  5. }  
  6. void print_value(int&& i)//右值  
  7. {  
  8.     std::cout << ”Rvalue:” << i << std::endl;  
  9. }  
  10.   
  11. int main()  
  12. {  
  13.     int i = 10;  
  14.     print_value(i);  
  15.     print_value(std::move(i));  
  16.     return 0;  
  17. }  
#include<iostream>
void print_value(int& i)//左值
{
    std::cout << "Lvalue:" << i << std::endl;
}
void print_value(int&& i)//右值
{
    std::cout << "Rvalue:" << i << std::endl;
}

int main()
{
    int i = 10;
    print_value(i);
    print_value(std::move(i));
    return 0;
}

最长用的交换函数
  1. void swap(T& a, T& b)  
  2. {  
  3.     T tmp = std::move(a);  
  4.     a = std::move(b);  
  5.     b = std::move(tmp);  
  6. }  
void swap(T& a, T& b)
{
    T tmp = std::move(a);
    a = std::move(b);
    b = std::move(tmp);
}
避免了3次拷贝。

move的本质,只是将参数转换为右值引用,并没有移动什么。因此要实现类关于右值得构造函数和复制操作符。move实现如下:
  1. template <typename T>  
  2. decltype (auto) move(T&& param){  
  3.     using ReturnType = remove_reference_t<T>&&;  
  4.     return static_cast<ReturnType>(param);  
  5. }  
template <typename T>
decltype (auto) move(T&& param){
    using ReturnType = remove_reference_t<T>&&;
    return static_cast<ReturnType>(param);
}


精确值传递

std::forward主要用于模板编程中,值传递的问题。可以推测参数是左值引用还是右值引用,精确传递值。参考这里:
http://blog.csdn.net/zwvista/article/details/6848582

猜你喜欢

转载自blog.csdn.net/wzw_ice/article/details/77754317
今日推荐