移动拷贝与移动赋值语句

本文介绍了C++中的左值和右值概念,左值可取地址且有名字,右值则无法取地址或无特定名字。通过示例代码展示了移动拷贝构造函数和移动赋值运算符的使用,它们在C++11中用于优化资源管理,尤其是处理临时对象。此外,还讨论了写实拷贝技术,即通过共享堆区资源来节省空间,避免不必要的复制。
摘要由CSDN通过智能技术生成

左值右值

概念:

  • 左值:可取地址,有具体名字

  • 右值:无法取地址或没有具体名字

int main()
{
    int a=10;//a 左值
    int& b=a;//引用左值
    int&& c =10;//10 右值,右值引用&&只能用来引用右值
    //int&& d=c;//c具有了名字,不可再用&&引用
    int&& d=Person(10);//右值引用可以用来引用没有名字的临时量(将亡值)
}

移动拷贝与移动赋值语句

概念:移动拷贝构造也称为右值拷贝构造。

当没有自己实现移动拷贝或移动赋值时,会调用拷贝构造和等号赋值重载,如果这两个也没有时,系统会调用默认生成的缺省移动拷贝与缺省移动赋值,本质就是浅拷贝浅赋值(按位操作)

class String
{
    char* str;
    String(char* p, int)//在加重载时,return时直接调用该构造,复制完后自动析构,回收p空间,防止内存泄漏            {               //int 用于标识区分公有的构造函数,达到重载效果
        str = p;
    }
public:
    String(const char* p = NULL) :str(NULL)//构造
    {
        if (p != NULL)
        {
            str = new char[strlen(p) + 1];
            strcpy_s(str,strlen(p)+1, p);
        }
        else//用来解决当构造对象时是缺省构造时:str=NULL,在赋值如果用来赋值的对象的str==NULL,就会造成系统崩溃
        {
            str = new char[1];//保证str至少在堆区开辟了一个字节的大小。
            *str = '\0';
        }
    }
    String(const String& src):str(NULL)//拷贝构造
    {
        str = new char[strlen(src.str )+1 ];
        strcpy_s(str, strlen(src.str)+1, src.str);
    }
    String& operator=(const String& src)//赋值
    {
        if (this != &src)
        {
            delete[] str;
            str = new char[strlen(src.str )+1];
            strcpy_s(str, strlen(src.str )+1, src.str);
        }
        return *this;
    }
    ~String()//析构函数
    {
        if (str != NULL)
        {
            delete[]str;
        }
        str = NULL;
    }
    .
    .
    .
    .
    String(String&& s)//移动拷贝构造
    {
        cout << "move copy construcgt :" << this << endl;
        str = s.str;//将s的资源直接给this
        s.str = NULL;//给s的str赋值空,在析构时不会再去释放堆中资源
    }
​
    String& operator=(String&& s)//移动赋值函数
    {
        if (this != &s)
        {
             delete []str;//防止this->指向的原先的地方有东西引发的内存泄漏。
            str = s.str;//将无名的临时量(将亡值)所指向的资源直接给给this
            s.str = NULL;//使临时量的str执行空,便于析构
             //s.str=Relese(s.str) :方法二,调用交换,将临时空间与待赋值的this所指向的资源进行交换
        }
        /*
        char* Relese(char *p)
        {
            char* old=str;
            str=p;
            return old;
        }
        */
        cout << this << "move operator=: " << endl;
        return *this;
    }
​
};
};
String fun()
{
    String s2("LCX");//构造s2
    return s2;//用s2构造将亡值,在C11标准下,如果实现了移动拷贝构造,那么在构造将亡值时将会对s2强转成右值,
              //return std::m 
              //接着调动移动拷贝构造,将s2作为参数传入
            
}
int main()
{
    String s1;//构造s1
​
    s1= fun();
    //1.调用fun函数
    //2.用将亡值对s1进行赋值时,调用的是移动赋值函数,直接将将亡值所指向的对空间给了s1
}

写实拷贝技术

写实拷贝技术:值对堆区的资源进行共享而不是一味的拷贝,节省空间

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string.h>
using namespace std;
class  String
{
private:
    struct StrNode//柔性数组
    {
        int ref;//引用对象的个数
        int len;//字符串长度
        int size;//字符串所在空间的大小
        char data[]; //不占空间是一个表示地址
    };
    StrNode* pstr;
public:
    String(const char* p = NULL) :pstr(NULL)
    {
        if (p != NULL)
        {
            int len = strlen(p);//计算P的大小
            pstr = (StrNode*)malloc(sizeof(StrNode) + len * 2 + 1);//开辟空间
            pstr->ref = 1;//引用数初始为1
            pstr->len = len;//字符串长度
            pstr->size = len * 2;//字符串空间大小
            strcpy(pstr->data, p);//把内容拷贝进来
        }
    }
    String(const String& s) :pstr(NULL)
    {
        pstr = s.pstr;
        pstr->ref += 1;//将引用数+1
    }
    ~String()
    {
        if (pstr!=NULL && --pstr->ref==0)//当pstr不为空且引用值减一等与0,可以释放资源
        {
            free(pstr);//释放空间
        }
        pstr = NULL;//pstr给空
​
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值