标准C++类std::string的内存共享,值得体会:

详见大牛:https://www.douban.com/group/topic/19621165/

顾名思义,内存共享,就是两个乃至更多的对象,共同使用一块内存;

1.关于string的内存共享问题:

通常,string类中必有一个私有成员,其是一个char*,用户记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存。

因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的,string类在返回这块内存地址时,只返回const char*,也就是只读的,

如果你要写,也只能通过string提供的方法进行数据的改写。

[cpp] view plaincopy
  1. #include<iostream>
  2. #include<string>
  3. #include<cstdio>
  4. using namespace std;
  5. main()
  6. {
  7. string str1 = "hello world";
  8. string str2 = str1;
  9. string str3 = str2;
  10. printf ("内存共享:\n");
  11. printf ("\tstr1 的地址: %x\n", (unsigned int)str1.c_str() );
  12. printf ("\tstr2 的地址: %x\n", (unsigned int)str2.c_str() );
  13. printf ("\tstr3 的地址: %x\n", (unsigned int)str3.c_str() );
  14. return 0;
  15. }

如上例子中,str1,str2,str3共享同一块内存,如图:

基本就是内存string类内存共享的最底层展现了,既然内存是一样的了,如果需要改写某个对象怎么办?由此引出写时拷贝Copy-On-Write

2.关于Copy-On-Write(原理)

顾名思义,写的时候在拷贝,(读的时候就不用了,哈哈)

还是以上边的例子为例:

[cpp] view plaincopy
  1. #include<iostream>
  2. #include<string>
  3. #include<cstdio>
  4. using namespace std;
  5. main()
  6. {
  7. string str1 = "hello world";
  8. string str2 = str1;
  9. string str3 = str2;
  10. printf ("内存共享:\n");
  11. printf ("\tstr1 的地址: %x\n", (unsigned int)str1.c_str() );
  12. printf ("\tstr2 的地址: %x\n", (unsigned int)str2.c_str() );
  13. printf ("\tstr3 的地址: %x\n", (unsigned int)str3.c_str() );
  14. str3[1]='a';
  15. str2[1]='w';
  16. str1[1]='q';
  17. printf ("通过写时拷贝之后:\n");
  18. printf ("\tstr1 的地址: %x\n", (unsigned int)str1.c_str() );
  19. printf ("\tstr2 的地址: %x\n", (unsigned int)str2.c_str() );
  20. printf ("\tstr3 的地址: %x\n", (unsigned int)str3.c_str() );
  21. return 0;
  22. }
  23. //输出结果:
  24. 内存共享:
  25.   str1 的地址: 83f9017
  26.   str2 的地址: 83f9017
  27.   str3 的地址: 83f9017
  28. 通过写时拷贝之后:
  29.   str1 的地址: 83f9017
  30.   str2 的地址: 83f9054
  31.   str3 的地址: 83f9034

很明显可以看出来,一开始,str1,str2,str3共享同一块内存,地址都是一样的;

当开始修改是这些内存是,先不说如何实现,先表征是如何写时拷贝的,看图,咱还是看图:

图中依然说明了str3的内容修改是怎么回事,str2的内容修改,也是同样的道理,重新给str2在堆上开辟空间,原空间只是str1一个人用,修改最后一个str1的内容时,

当然就不用在和前两种一样啦,因为,这个时候,原空间只有str1一个人用,这个时候,对此空间操作,没有任何问题。都写都可以;

写时拷贝在此例中的体现,主要是str2,和str3内容的修改;但是有没有发现,我每次开辟空间的同时,会在新开辟的空间开头多分配一个空间,存放的是count;

原因就和写时拷贝的具体操作有关了:

3.写时拷贝(Copy-On-Write)的实现:

Copy-On-Write使用了“引用计数”,有一个变量count来计数,而且计数就放在没开辟一段空间的开头几个字节。

当第一个类构造时,string的构造函数会根据传入的参数从堆上分配内存,当有其它类需要这块内存时,这个计数为自动累加,

当有类析构时,这个计数会减一,直到最后一个类析构时,此时的count为1或是0,此时,程序才会真正的Free这块从堆上分配的内存。

下面是我写的一个简单的例子:

[cpp] view plaincopy
  1. #include<iostream>
  2. using namespace std;
  3. class String
  4. {
  5. public:
  6. String(const char* str)
  7. //初始时字符创有一个\0外加4个字节的引用计数空间
  8. :_str(new char[strlen(str)+5])
  9. {
  10. (*((int*)_str)) = 1;//申请的空间赋值为1
  11. _str += 4; //让_str还是指向字符创的第一个字符
  12. //而不是引用计数的头上
  13. strcpy(_str,str);
  14. }
  15. String(const String& s)
  16. :_str(s._str)
  17. {
  18. (*(((int*)_str) - 1)) += 1;
  19. }
  20. String& operator=(const String& s)
  21. {
  22. if(_str != s._str)
  23. {
  24. if(*(((int*)_str) - 1) == 0)
  25. {
  26. delete[] (_str-4);
  27. }
  28. _str = s._str;
  29. *(((int*)_str) - 1) += 1;
  30. }
  31. return *this;
  32. }
  33. ~String()
  34. {
  35. if(*(((int*)_str) - 1) == 0)
  36. {
  37. _str -= 4;
  38. delete[] _str;
  39. }
  40. }
  41. private:
  42. char *_str;
  43. };
  44. void Test()
  45. {
  46. String s1("11111111111111111111111111");
  47. String s2(s1);
  48. }
  49. int main()
  50. {
  51. Test();
  52. return 0;
  53. }

在内存开头开辟引用计数空间;

到此,string类的内存共享和写时拷贝,就算是告一段落了,个人拙见,跪求赐教!

转载于:https://www.cnblogs.com/zhoug2020/p/6542286.html

标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)相关推荐

  1. string类的写时拷贝

    由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃. 实现string类的时候通常显示的定义拷贝构造函数和运算符重载函数. 由于释放内存空间,开辟内存空间时花费时 ...

  2. 【C++标准库】std::string用法指南源码剖析

    文章目录 1.ASCII码 (1)计算机如何表达字符 2.C 语言中的字符类型 char (1)思想:char 即整数 (3)C 语言帮手函数 (4)C语言中的字符串 (4)C 语言转义符 3.C++ ...

  3. C++ String类写时拷贝 4

    http://blog.51cto.com/zgw285763054/1839752 维基百科: 写入时复制(英语:Copy-on-write,简称COW)是一种计算机程序设计领域的优化策略.其核心思 ...

  4. c++ string类深拷贝其他版本(简洁版,引用计数版,写时拷贝版)

    简洁版: class String { public:String(char* pStr=""){if(pStr==NULL){_pStr=new char[0];_pStr='\ ...

  5. 浅拷贝+引用计数--写时拷贝---模拟实现string容器

    引用计数 深拷贝 多个对象共享同一份资源时,最后能够保证该资源只被释放一次 应该由哪个对象释放资源? 由最后一个使用该资源的对象去释放 怎么知道一个对象是最后一个使用该资源的对象? 给一个计数,记录使 ...

  6. String写时拷贝实现

    头文件部分 1 /* 2 版权信息:狼 3 文件名称:String.h 4 文件标识: 5 摘 要:对于上版本简易的String进行优化跟进. 6 改进 7 1.(将小块内存问题与大块分别对待)小内存 ...

  7. C++:String的写时拷贝

    String的写时拷贝 //test.h #pragma once#include <iostream> #include <string.h> #include <cs ...

  8. C++字符串类std::string介绍

    std::string是最常用的字符串类,下面介绍下该类的一些成员函数 参考文档 1 构造函数 1.1 string() std::string str; 1.2 string(const strin ...

  9. 【Linux】虚拟地址空间 --- 虚拟地址、空间布局、内存描述符、写时拷贝、页表…

    该吃吃,该喝喝,遇事儿别往心上隔

最新文章

  1. 学习PCL库你应该知道的C++特性
  2. JavaScript-内存空间
  3. NSA泄露的恶意软件DoublePulsar感染了数万台Windows电脑
  4. 为什么梯度反方向是函数下降最快的方向
  5. 北理工在线作业计算机的主要特点是( ),北理工18秋《计算机组成原理》在线作业【答案】...
  6. bzoj2208 [Jsoi2010]连通数
  7. 【BZOJ】【3295】【CQOI2011】动态逆序对
  8. css圆角box(宽度自适应)(百度知道挖出)
  9. 自定义类型详解:结构体(内存对齐、位段) + 枚举 + 联合
  10. 剪枝乱炖 | 模型加速与压缩
  11. vs2008的预编译命令
  12. 做自己最好的生活大师
  13. 解决宿舍路由器校园网共享登陆问题
  14. tx2 GPIO使用教程
  15. 为什么要创建SRT?
  16. Javascript运行环境
  17. Kurl——轻量化http-authentication在线暴破工具
  18. 湖南师范大学计算机专业研究生读几年,湖南师范大学计算机专业在职研究生培养方式是怎样的?...
  19. 华为手机怎么编辑PDF?一款神器轻松搞定
  20. kali系统升级(包含软件信息、所有软件、整个系统)

热门文章

  1. mysql 乐观锁_使用Mysql乐观锁解决并发问题
  2. 如何进行聚类可视化_如何使用matplotlib包进行数据可视化
  3. 对Kalman Filter的理解
  4. UVC协议USB视频捕获设备定义
  5. 航海学校高级课程任务讲义--海事课程
  6. Lua中的metatable
  7. 谷歌 colab_使用Google Colab在Python中将图像和遮罩拆分为多个部分
  8. opencv 分割边界_电影观众:场景边界分割
  9. 广东省那么发达,为什么还有全国贫困县?
  10. 信用贷款额度是怎么确定的?