• c++11 移动语义


    c++11 移动语义

    #define _CRT_SECURE_NO_WARNINGS
    
    #include <iostream>
    #include <string>
    #include <vector>
    #include <map>
    
    // C++中还有一个被广泛认同的说法,那就是可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值。
    // 相对于左值,右值表示字面常量、表达式、函数的非引用返回值等。
    
    /*
    右值引用是用来支持转移语义的。
    转移语义可以将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁,能够大幅度提高 C++ 应用程序的性能。临时对象的维护 ( 创建和销毁 ) 对性能有严重影响。
    
    转移语义是和拷贝语义相对的,可以类比文件的剪切与拷贝,当我们将文件从一个目录拷贝到另一个目录时,速度比剪切慢很多。
    
    通过转移语义,临时对象中的资源能够转移其它的对象里。
    */
    
    /*
    移动语义定义: 
    在现有的 C++ 机制中,我们可以定义拷贝构造函数和赋值函数。
    要实现转移语义,需要定义转移构造函数,还可以定义转移赋值操作符。
    对于右值的拷贝和赋值会调用转移构造函数和转移赋值操作符。
    如果转移构造函数和转移拷贝操作符没有定义,那么就遵循现有的机制,拷贝构造函数和赋值操作符会被调用。
    普通的函数和操作符也可以利用右值引用操作符实现转移语义。
    */
    class MyString
    {
    public:
        MyString(const char *tmp = "abc")
        {//普通构造函数
            len = strlen(tmp);  //长度
            str = new char[len+1]; //堆区申请空间
            strcpy(str, tmp); //拷贝内容
    
            cout << "普通构造函数 str = " << str << endl;
        }
    
        MyString(const MyString &tmp)
        {//拷贝构造函数
            len = tmp.len;
            str = new char[len + 1];
            strcpy(str, tmp.str);
    
            cout << "拷贝构造函数 tmp.str = " << tmp.str << endl;
        }
    
        //移动构造函数
        //参数是非const的右值引用
        MyString(MyString && t)
        {
            str = t.str; //拷贝地址,没有重新申请内存
            len = t.len;
    
            //原来指针置空
            t.str = NULL;
            cout << "移动构造函数" << endl;
        }
    
        MyString &operator= (const MyString &tmp)
        {//赋值运算符重载函数
            if(&tmp == this)
            {
                return *this;
            }
    
            //先释放原来的内存
            len = 0;
            delete []str;
    
            //重新申请内容
            len = tmp.len;
            str = new char[len + 1];
            strcpy(str, tmp.str);
    
            cout << "赋值运算符重载函数 tmp.str = " << tmp.str << endl;
    
            return *this;
    
        }
    
        //移动赋值函数
        //参数为非const的右值引用
        MyString &operator=(MyString &&tmp)
        {
            if(&tmp == this)
            {
                return *this;
            }
    
            //先释放原来的内存
            len = 0;
            delete []str;
    
            //无需重新申请堆区空间
            len = tmp.len;
            str = tmp.str; //地址赋值
            tmp.str = NULL;
    
            cout << "移动赋值函数
    ";
    
            return *this;
        }
    
        ~MyString()
        {//析构函数
            cout << "析构函数: ";
            if(str != NULL)
            {
                cout << "已操作delete, str =  " << str;
                delete []str;
                str = NULL;
                len = 0;
    
            }
            cout << endl;
        }
    
    private:
        char *str = NULL;
        int len = 0;
    };
    
    MyString func() //返回普通对象,不是引用
    {
        MyString obj("mike");
    
        return obj;
    }
    
    void mytest()
    {
        MyString &&tmp1 = func(); //右值引用接收
    
        MyString tmp2("abc"); //实例化一个对象
        tmp2 = func();
    
        return;
    }
    
    int main()
    {
        mytest();
    
        system("pause");
        return 0;
    }
  • 相关阅读:
    剑指Offer_栈的压入序列是否有对应的弹出序列
    剑指Offer_Java_顺时针打印矩阵(二维数组)
    排序算法Java代码实现(四)—— 归并排序
    排序算法Java代码实现(六)—— 堆排序
    排序算法Java代码实现(五)—— 快速排序
    排序算法Java代码实现(三)—— 插入排序 和 希尔排序
    CSS sprites
    局部变量和参数传递的问题
    隐藏元素的方式有哪些
    box-sizing属性的的用法
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/7787608.html
Copyright © 2020-2023  润新知