zoukankan      html  css  js  c++  java
  • C++11右值引用

    C++11右值引用

    1、什么是左值?什么是右值?

      左值是表达式结束后依然存在的对象;右值是表达式结束时就不再存在的对象。

    2、在早期的C++中,普通 & 无法对右值取引用。只有 const & 可以对右值取引用。

    const int& i = 10;

      

      右值引用能够解决两个问题。

        1)非必要的拷贝操作
        2)模板函数,按照实际类型进行转发

    3、第一大特点:通过右值引用的声明,右值又“重获新生”

    #include <iostream>
    using namespace std;
    
    int g_constructCount=0;
    int g_copyConstructCount=0;
    int g_destructCount=0;
    struct A
    {
        A(){
            cout<<"construct: "<<++g_constructCount<<endl;    
        }
        
        A(const A& a)
        {
            cout<<"copy construct: "<<++g_copyConstructCount <<endl;
        }
        ~A()
        {
            cout<<"destruct: "<<++g_destructCount<<endl;
        }
    };
    
    A GetA()
    {
        return A();
    }
    
    int main() {
        A a = GetA();
        return 0;
    }
    View Code

        上面代码,会产生如下输出 :

    construct: 1
    copy construct: 1
    destruct: 1
    copy construct: 2
    destruct: 2
    destruct: 3

        如果将 A a  = GetA(); 改为下在这样,会产生编译错误。

    A& a = GetA()

      改为 A&& a = GetA() 是可以的。会产生如下输出 :

    construct: 1
    copy construct: 1
    destruct: 1
    destruct: 2

    4、第二大特点,右值引用本身可能是左传,也可能是右值。

    template<typename T>
    void f(T&& t){}
    
    f(10); //t是右值
    
    int x = 10;
    f(x); //t是左值

    5、第三大特点,universal references. T&& t在发生自动类型推断的时候,如果被一个左值初始化,它就是一个左值;如果它被一个右值初始化,它就是一个右值,它是左值还是右值取决于它的初始化。

    template<typename T>
    void f(T&& param); 
    
    template<typename T>
    class Test {
        Test(Test&& rhs); 
    };

    6、为了避免 copy constructor 中内存很大的问题,C++11中新增了 move constructor.

      copy constructor 中做深拷贝。 move constructor 中做浅拷贝,并且将参数中的数据reset。

    class A
    {
    public:
        A() :m_ptr(new int(0)){}
        A(const A& a):m_ptr(new int(*a.m_ptr)) //深拷贝的拷贝构造函数
        {
            cout << "copy construct" << endl;
        }
        A(A&& a) :m_ptr(a.m_ptr)
        {
            a.m_ptr = nullptr;
            cout << "move construct" << endl;
        }
        ~A(){ delete m_ptr;}
    private:
        int* m_ptr;
    };
    int main(){
        A a = Get(false); 
    } 
    construct
    move construct
    move construct

    7、std::move的作用是什么?

      

      std::move用于把任意类型转化为右值引用,以方便调用move构造函数/move赋值函数。

    8、std::forward的作用是什么?把左值引用还原为左值,把右值引用还原为右值,即把尽可能把值变变右值。

    template <typename T>
    void forwardValue(T& val)
    {
        processValue(val); //右值参数会变成左值 
    }
    template <typename T>
    void forwardValue(const T& val)
    {
        processValue(val); //参数都变成常量左值引用了 
    }

      如果调用 fworwardValue(0),则 processValue(val)时,参数变成了左值引用。

      forward<T>的目的是保护引用类型。

     3、四大类型

        1)non-const lvalue

        2)const lvalue

        3)non-const rvalue

        4)const rvalue

     4、为什么non-const lvalue只能绑定到本类对象?

        首先因为const的限制non-const只能绑定到non-const,因此排除(2)、(4),再者如果绑定到non-const rvalue,则有可能导致在后续修改rvalue,这显然有巨大风险。

     5、为什么non-const rvalue只能绑定到本类对象?

        如果允许绑定到non-const lvalue,则有可能导致数据被窃取;如果绑定到const rvalue,const lvalue则有可能修改原数据。

     6、template<typename T >

        void f(T&& t){ g(t); }

      我们规定:

        如果实参类型为右值,那么T&&就被推导为右值引用。

        如果实参类型为左值,那么T&&就被推导为左值引用。

     7、有了右值引用后,需要添加以下类成员函数:

      1)右值引用构造函数。

      2)右值引用拷贝构造函数。

     参考:

     1、http://www.cnblogs.com/likaiming/p/9029908.html

     2、http://blog.csdn.net/pongba/article/details/1697636

  • 相关阅读:
    信号量
    队列 Queue JoinableQueue
    process 多进程写法 multiprocessing
    socketserver
    scokte tcp/ip
    线程池或进程池的回调函数
    gevent 真正的协程
    巨蟒python全栈开发flask12项目开始4
    巨蟒python全栈开发flask11项目开始3
    巨蟒python全栈开发flask10 项目开始2
  • 原文地址:https://www.cnblogs.com/tekkaman/p/3496773.html
Copyright © 2011-2022 走看看