左值右值
概念:
-
左值:可取地址,有具体名字
-
右值:无法取地址或没有具体名字
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给空 } };