• C++11_ 右值引用


    版权声明:本文为博主原创文章,未经博主允许不得转载。

    由于右值所产生的临时变量问题一直是一种诟病,C++11中引入了右值引用这个核心语言机制,来提升运行期性能. 

    首先我先说明一下什么是左值和右值: 左值和右值都是针对表达式而言的,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象

    int b = 20;   //这里b是左值 20是右值 ,因为这个表达式过后 20将不存在了  而b依然存在
                  //同时也可以根据能否取地址来判断是否是左值(能取地址)还是右值(不能取地址),如本例中  20不能取地址顾为右值

    右值引用一般都用&&来修饰

    下面我们来证实一下上面的右值判断

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void process(int& i)//右值引用
    {
        cout << "process(int&): " << i << endl;
    }
    void process(int&& i)//左值引用
    {
        cout << "process(int&&): " << i << endl;
    }
    void forward(int&& i)//中间函数
    {
        cout << "forward(int&&): " << i << ",  ";
        process(i);
    //    process(std::forward<int>(i));
    }
    
    int main(int argc, const char * argv[]) {
     
        int a = 0;
        
        process(a);
        
        process(1);
        
        forward(1); //不完美的转交 右值传递后 却调用左值 原因转交过程中转变成一个named obj
        
        forward(move(a));//强制转换为右值 也不好用 std::move()强制转换为右值引用
        
        return 0;
    }

    输出结果

    是不是发现了调用中间函数的时候丢了什么,把右值引用丢了.使用std::forward<T>()可以避免这种现象(上面的注释部分).


    下面我们开始研究一下move()

    move(),其实类似于浅拷贝,也可以理解成"偷"

    下面我们来实现一个带右值引用的类


    这个是不带右值引用的

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class Person
    {
        
    private:
        int _age;
        char* _name;
        size_t _len;
        void _test_name(const char *s)
        {
            _name = new char[_len+1];
            memcpy(_name, s, _len);
            _name[_len] = '';
        }
        
    public:
        //default ctor
        Person(): _age(0) , _name(NULL), _len(0){cout<<"default cotr"<< endl;}
        
        Person(const int age, const char * p) : _age(age), _len(strlen(p)) {
            _test_name(p);
            cout<<"cotr"<<endl;
        }
        
        //dctor
        ~Person(){
            if(_name){
                delete _name;
            }
            cout<<"default dctor"<<endl;
        }
        
        // copy ctor
        Person (const Person& p):_age(p._age),_len(p._len){
            _test_name(p._name);
            cout<<"copy ctor"<<endl;}
        
        //copy assignment
        Person & operator=(const Person& p)
        {
            if (this != &p){
                if(_name) delete _name;
                _len = p._len;
                _age = p._age;
                _test_name(p._name);
            }
            else{
                cout<< "self Assignment. Nothing to do." <<endl;
            }
            cout<<"copy assignment"<<endl;
            return *this;
        }
    };

    int main(int argc, const char * argv[]) { Person * obj = new Person(); vector<Person> v1; v1.push_back(*obj); delete obj; return 0; }

    输出结果


    带右值引用的 

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class Person
    {
        
    private:
        int _age;
        char* _name;
        size_t _len;
        void _test_name(const char *s)
        {
            _name = new char[_len+1];
            memcpy(_name, s, _len);
            _name[_len] = '';
        }
        
    public:
        //default ctor
        Person(): _age(0) , _name(NULL), _len(0){cout<<"default cotr"<< endl;}
        
        Person(const int age, const char * p) : _age(age), _len(strlen(p)) {
            _test_name(p);
            cout<<"cotr"<<endl;
        }
        
        //dctor
        ~Person(){
            if(_name){
                delete _name;
            }
            cout<<"default dctor"<<endl;
        }
        
        // copy ctor
        Person (const Person& p):_age(p._age),_len(p._len){
            _test_name(p._name);
            cout<<"copy ctor"<<endl;}
        
        //copy assignment
        Person & operator=(const Person& p)
        {
            if (this != &p){
                if(_name) delete _name;
                _len = p._len;
                _age = p._age;
                _test_name(p._name);
            }
            else{
                cout<< "self Assignment. Nothing to do." <<endl;
            }
            cout<<"copy assignment"<<endl;
            return *this;
        }
        
        // move cotr , wihth "noexcept"
        Person(Person&& p) noexcept :_age(p._age) , _name(p._name), _len(p._len){
            cout<<"move ctor"<<endl;
            p._age = 0;
            p._name = NULL;//必须为NULL 如果你把这里设为空 那么这个函数走完之后将调用析够函数 因为当前的Person类 和你将要析够的Person的_name指向同一部分 析构部分见析构函数
        }
        // move assignment
        Person& operator=(Person&& p) noexcept {
            
            if (this != &p)
            {
                if(_name) delete _name;
                _age  = p._age;
                _len  = p._len;
                _name = p._name;
                p._age  = 0;
                p._len  = 0;
                p._name = NULL;
            }
            cout<<"move assignment"<<endl;
            return *this;
        }
    };

    int main(int argc, const char * argv[]) { Person * obj = new Person(); vector<Person> v1; v1.push_back(move(*obj)); delete obj; return 0; }

    输出结果

    可以见到少调用一次构造函数.以上就是右值引用的简单实现了.

     参照<<侯捷 C++新标准 C++11>>

  • 相关阅读:
    C# 获取文件名及扩展名
    Javscript调用iframe框架页面中函数的方法
    jquery事件重复绑定的几种解决方法 (二)
    Jquery 点击事件重复获取叠加 (一)
    .NET 即时通信,WebSocket服务端实例
    .Net ASP.NET 打开指定文件夹
    动态 hover 使用变相使用
    给 layui upload 带每个文件的进度条, .net 后台代码
    layui upload 后台获取不到值
    ECharts配置项之title(标题)
  • 原文地址:https://www.cnblogs.com/LearningTheLoad/p/7226805.html
Copyright © 2020-2023  润新知