首页IT科技c++中的深拷贝和浅拷贝(C++Day09 深拷贝、写时复制(cow)、短字符串优化)

c++中的深拷贝和浅拷贝(C++Day09 深拷贝、写时复制(cow)、短字符串优化)

时间2025-07-10 05:34:38分类IT科技浏览4898
导读:一、std::string 的底层实现...

一              、std::string 的底层实现

1                     、深拷贝

这种实现方式              ,在需要对字符串进行频繁复制而又并不改变字符串内容时                     ,效率比较低下              。如果对一块空间只是进行读       ,就没必要采用深拷贝       ,当需要进行写的时候                     ,再使用深拷贝申请新的空间

2       、写时复制 (浅拷贝+引用计数)

当只是进行读操作时              ,就进行浅拷贝       ,如果需要进行写操作的时候                     ,再进行深拷贝;再加一个引用计数              ,多个指针指向同一块空间,记录同一块空间的对象个数

std::string之写时复制

当两个std::string发生复制或者赋值时                     ,不会复制字符串内容                     ,而是增加一个引用计数,然后字符串指针进行浅拷贝              ,其执行效率为O(1)                     。只有当修改其中一个字符串内容时                     ,才执行真正的复制       。

引用计数存在哪里?

堆区       ,为了好获取将将引用计数与数据放在一起              ,并且最好在数据前面                     ,这样当数据变化的时候不会移动引用计数的位置

1 class String{ 2 public: 3 String():m_str(new char[5]() + 4){ 4 //new 5 表示4个字节存放引用计数       ,一个字节存放\0 +4 是为了将指针指向字符串位置 5 cout << "String()" << endl; 6 //引用计数初始化为1 (字符指针向前偏移       ,指向引用计数                     ,并且转为int型指针              ,解引用得引用计数的值) 7 InitRefCount(); 8 } 9 10 String(const char* str):m_str(new char[strlen(str) + 5] + 4){ //有参构造 11 //申请空间大小       ,4B引用计数                     ,还有\0 12 cout << "Sting(const char *)" << endl; 13 strcpy(m_str, str); 14 InitRefCount(); 15 } 16 17 String(const String &rhs):m_str(rhs.m_str){ //浅拷贝 18 cout << "String(const String &rhs)" << endl; 19 IncreaseRefCount(); 20 } 21 22 String &operator=(const String &rhs){ //赋值 23 if(this != &rhs){ 24 DecreaseRefCount(); 25 if(0 == getRefcount()){ //如果该空间引用计数为0              ,删掉该空间 26 delete [] (m_str - 4); 27 } 28 m_str = rhs.m_str; //浅拷贝,引用计数++ 29 IncreaseRefCount(); 30 } 31 return *this; 32 } 33 private: 34 //CharProxy中去重载=与<<运算符                     ,争对读写有不同的操作 35 class CharProxy{ 36 public: 37 CharProxy(String &self, size_t idx):_self(self), _idx(idx){ 38 39 } 40 //写操作 41 char &operator=(const char &ch); //string是不完整类型                     ,所以要在类外实现 42 //读操作 43 friend std::ostream &operator<<(std::ostream &os, const CharProxy &rhs); 44 45 private: 46 String &_self; //CharProxy在string里面写,是不完整类型              ,无法创建对象 47 size_t _idx; //self找到m_pstr                     ,可以去下标       ,去除string中每一个字符 48 }; 49 50 public: 51 52 CharProxy operator[](size_t idx){ 53 return CharProxy(*this, idx); //临时对象              ,所以不能返回引用 54 } 55 56 #if 0 这样去重载[]                     ,无法区分读写操作 若对s1[0]进行读       ,依然会修改引用计数 57 char &operator[](size_t idx){ 58 if(idx < size()){ 59 if(getRefcount() > 1){ //共享空间       ,[idx]修改时进行深拷贝 60 char *tmp = new char[size() + 5]() + 4; //深拷贝 61 strcpy(tmp, m_str); 62 DecreaseRefCount(); 63 m_str = tmp; //浅拷贝 64 InitRefCount(); 65 } 66 return m_str[idx]; 67 }else{ 68 static char charNull = \0; 69 return charNull; 70 } 71 } 72 #endif 73 ~String(){ 74 75 DecreaseRefCount(); 76 if(0 == getRefcount()){ 77 78 delete [] (m_str - 4); 79 } 80 } 81 82 int getRefcount() const{ //获取引用计数 83 return *(int*)(m_str - 4); 84 } 85 86 const char* c_str() const{ 87 return m_str; 88 } 89 90 size_t size() const{ 91 return strlen(m_str); 92 } 93 94 friend std::ostream &operator<<(std::ostream &os, const String::CharProxy &rhs); 95 friend std::ostream &operator<<(std::ostream &os, const String &rhs); 96 private: 97 char *m_str; 98 /* static int refCount; //静态变量为所有对象所共享,无法表示不同对象的引用计数 */ 99 100 void InitRefCount(){ //初始化引用计数 101 *(int*)(m_str - 4) = 1; 102 } 103 104 void IncreaseRefCount(){ //引用计数++ 105 ++*(int*)(m_str - 4); 106 } 107 108 void DecreaseRefCount(){ //引用计数-- 109 --*(int*)(m_str - 4); 110 } 111 }; 112 113 114 std::ostream &operator<<(std::ostream &os, const String &rhs){ 115 if(rhs.m_str){ 116 os << rhs.m_str; 117 } 118 return os; 119 } 120 121 //写操作 122 char &String:: CharProxy::operator=(const char &ch){ 123 if(_idx < _self.size()){ 124 if(_self.getRefcount() > 1){ //共享空间                     ,[idx]修改时进行深拷贝 125 char *tmp = new char[_self.size() + 5]() + 4; //深拷贝 126 strcpy(tmp, _self.m_str); 127 _self.DecreaseRefCount(); 128 _self.m_str = tmp; //浅拷贝 129 _self.InitRefCount(); 130 } 131 _self.m_str[_idx] = ch; //真正的写操作 132 return _self.m_str[_idx]; 133 }else{ 134 static char charNull = \0; 135 return charNull; 136 } 137 138 } 139 140 std::ostream &operator<<(std::ostream &os, const String::CharProxy &rhs){ 141 os << rhs._self.m_str[rhs._idx]; 142 return os; 143 }

测试代码:

1 void test(){ 2 3 String s1("hello"); 4 cout << "s1 = " << s1 << endl; 5 cout << "s1.getRefcount()" << s1.getRefcount() << endl; 6 printf("s1 address is %p\n", s1.c_str()); 7 8 cout << endl << endl; 9 String s2 = s1; 10 cout << "s1 = " << s1 << endl; 11 cout << "s2 = " << s2 << endl; 12 cout << "s1.getRefcount()" << s1.getRefcount() << endl; 13 cout << "s2.getRefcount()" << s2.getRefcount() << endl; 14 printf("s1 address is %p\n", s1.c_str()); 15 printf("s2 address is %p\n", s2.c_str()); 16 17 cout << endl << endl; 18 String s3("world"); 19 cout << "s3" << s3 << endl; 20 cout << "s3.getRefcount()" << s3.getRefcount() << endl; 21 printf("s3 address is %p\n", s3.c_str()); 22 23 cout << endl << endl; 24 s3 = s1; 25 cout << "s1 = " << s1 << endl; 26 cout << "s2 = " << s2 << endl; 27 cout << "s3 = " << s3 << endl; 28 cout << "s1.getRefcount()" << s1.getRefcount() << endl; 29 cout << "s2.getRefcount()" << s2.getRefcount() << endl; 30 cout << "s3.getRefcount()" << s3.getRefcount() << endl; 31 printf("s1 address is %p\n", s1.c_str()); 32 printf("s2 address is %p\n", s2.c_str()); 33 printf("s3 address is %p\n", s3.c_str()); 34 35 cout << endl << "对s3执行写操作" << endl; 36 //s3.operator[](idx) 37 //CharProxy = char; 38 s3[0] = H; 39 cout << "s1 = " << s1 << endl; 40 cout << "s2 = " << s2 << endl; 41 cout << "s3 = " << s3 << endl; 42 cout << "s1.getRefcount()" << s1.getRefcount() << endl; 43 cout << "s2.getRefcount()" << s2.getRefcount() << endl; 44 cout << "s3.getRefcount()" << s3.getRefcount() << endl; 45 printf("s1 address is %p\n", s1.c_str()); 46 printf("s2 address is %p\n", s2.c_str()); 47 printf("s3 address is %p\n", s3.c_str()); 48 49 cout << endl << "对s1[0]执行读操作" << endl; 50 //cout << CharProxy 51 cout << "s1[0] = " << s1[0] << endl; 52 cout << "s1 = " << s1 << endl; 53 cout << "s2 = " << s2 << endl; 54 cout << "s3 = " << s3 << endl; 55 cout << "s1.getRefcount()" << s1.getRefcount() << endl; 56 cout << "s2.getRefcount()" << s2.getRefcount() << enl; 57 cout << "s3.getRefcount()" << s3.getRefcount() << endl; 58 printf("s1 address is %p\n", s1.c_str()); 59 printf("s2 address is %p\n", s2.c_str()); 60 printf("s3 address is %p\n", s3.c_str()); 61 }

3       、短字符串优化

核心思想:发生拷贝时要复制一个指针              ,对小字符串来说       ,为啥不直接复制整个字符串呢                     ,说不定还没有复制一个指针的代价大(小字符串复制指针              ,大字符串复制字符串)

声明:本站所有文章,如无特殊说明或标注                     ,均为本站原创发布       。任何个人或组织                     ,在未征得本站同意时,禁止复制                     、盗用              、采集       、发布本站内容到任何网站                     、书籍等各类媒体平台                     。如若本站内容侵犯了原著者的合法权益              ,可联系我们进行处理              。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
海洋cms ssl(海洋CMS抓取:助力网站内容管理的神器) 怎样提升网站搜索引擎排名(网站搜索引擎排名提高的要点是什么)