標準C++類std::string的內存共享和Copy-On-Write(寫時拷貝)

標準C++類std::string的內存共享,值得體會:

詳見大牛:https://www.douban.com/group/topic/19621165/

顧名思義,內存共享,就是兩個乃至更多的對象,共同使用一塊內存;

1.關于string的內存共享問題:

通常,string類中必有一個私有成員,其是一個char*,用戶記錄從堆上分配內存的地址,其在構造時分配內存,在析構時釋放內存。

因為是從堆上分配內存,所以string類在維護這塊內存上是格外小心的,string類在返回這塊內存地址時,只返回const char*,也就是只讀的,

如果你要寫,也只能通過string提供的方法進行數據的改寫。

[cpp] view plaincopy 在CODE上查看代碼片派生到我的代碼片
  1. #include<iostream>??
  2. #include<string>??
  3. #include<cstdio>??
  4. using?namespace?std;??
  5. ???
  6. main()??
  7. {??
  8. ???????string?str1?=?"hello?world";??
  9. ???????string?str2?=?str1;??
  10. ???????string?str3?=?str2;??
  11. ????
  12. ???????printf?("內存共享:\n");??
  13. ???????printf?("\tstr1?的地址:?%x\n",?(unsigned?int)str1.c_str()?);??
  14. ???????printf?("\tstr2?的地址:?%x\n",?(unsigned?int)str2.c_str()?);??
  15. ???????printf?("\tstr3?的地址:?%x\n",?(unsigned?int)str3.c_str()?);??
  16. ??
  17. ???????return?0;??
  18. }??
如上例子中,str1,str2,str3共享同一塊內存,如圖:


基本就是內存string類內存共享的最底層展現了,既然內存是一樣的了,如果需要改寫某個對象怎么辦?由此引出寫時拷貝Copy-On-Write

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

顧名思義,寫的時候在拷貝,(讀的時候就不用了,哈哈)

還是以上邊的例子為例:

[cpp] view plaincopy 在CODE上查看代碼片派生到我的代碼片
  1. #include<iostream>??
  2. #include<string>??
  3. #include<cstdio>??
  4. using?namespace?std;??
  5. ???
  6. main()??
  7. {??
  8. ???????string?str1?=?"hello?world";??
  9. ???????string?str2?=?str1;??
  10. ???????string?str3?=?str2;??
  11. ????
  12. ???????printf?("內存共享:\n");??
  13. ???????printf?("\tstr1?的地址:?%x\n",?(unsigned?int)str1.c_str()?);??
  14. ???????printf?("\tstr2?的地址:?%x\n",?(unsigned?int)str2.c_str()?);??
  15. ???????printf?("\tstr3?的地址:?%x\n",?(unsigned?int)str3.c_str()?);??
  16. ??
  17. ???????str3[1]='a';??
  18. ???????str2[1]='w';??
  19. ???????str1[1]='q';??
  20. ????
  21. ???????printf?("通過寫時拷貝之后:\n");??
  22. ???????printf?("\tstr1?的地址:?%x\n",?(unsigned?int)str1.c_str()?);??
  23. ???????printf?("\tstr2?的地址:?%x\n",?(unsigned?int)str2.c_str()?);??
  24. ???????printf?("\tstr3?的地址:?%x\n",?(unsigned?int)str3.c_str()?);??
  25. ??
  26. ???????return?0;??
  27. }??
  28. ??
  29. //輸出結果:??
  30. 內存共享:??
  31.   str1?的地址:?83f9017??
  32.   str2?的地址:?83f9017??
  33.   str3?的地址:?83f9017??
  34. 通過寫時拷貝之后:??
  35.   str1?的地址:?83f9017??
  36.   str2?的地址:?83f9054??
  37.   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 在CODE上查看代碼片派生到我的代碼片
  1. #include<iostream>??
  2. using?namespace?std;??
  3. ??
  4. class?String??
  5. {??
  6. public:??
  7. ????String(const?char*?str)??
  8. ????????//初始時字符創有一個\0外加4個字節的引用計數空間??
  9. ????????:_str(new?char[strlen(str)+5])??
  10. ????{??
  11. ????????(*((int*)_str))?=?1;//申請的空間賦值為1??
  12. ????????_str?+=?4;?//讓_str還是指向字符創的第一個字符??
  13. ???????????????????//而不是引用計數的頭上??
  14. ????????strcpy(_str,str);??
  15. ????}??
  16. ??
  17. ????String(const?String&?s)??
  18. ????????:_str(s._str)??
  19. ????{??
  20. ????????(*(((int*)_str)?-?1))?+=?1;??
  21. ????}??
  22. ??
  23. ????String&?operator=(const?String&?s)??
  24. ????{??
  25. ????????if(_str?!=?s._str)??
  26. ????????{??
  27. ????????????if(*(((int*)_str)?-?1)?==?0)??
  28. ????????????{??
  29. ????????????????delete[]?(_str-4);??
  30. ????????????}??
  31. ????????????_str?=?s._str;??
  32. ????????????*(((int*)_str)?-?1)?+=?1;??
  33. ????????}??
  34. ????????return?*this;??
  35. ??
  36. ??
  37. ????}??
  38. ????~String()??
  39. ????{??
  40. ????????if(*(((int*)_str)?-?1)?==?0)??
  41. ????????{??
  42. ????????????_str?-=?4;??
  43. ????????????delete[]?_str;??
  44. ????????}??
  45. ????}??
  46. private:??
  47. ????char?*_str;??
  48. };??
  49. ??
  50. void?Test()??
  51. {??
  52. ????String?s1("11111111111111111111111111");??
  53. ????String?s2(s1);??
  54. }??
  55. ??
  56. int?main()??
  57. {??
  58. ????Test();??
  59. ????return?0;??
  60. }??
在內存開頭開辟引用計數空間;

到此,string類的內存共享和寫時拷貝,就算是告一段落了,個人拙見,跪求賜教!

轉載于:https://www.cnblogs.com/zhoug2020/p/6542286.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253156.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253156.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253156.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常用類一一枚舉類一一定義和調用

package test;public class EnumTest {/**枚舉* */public static void main(String[] args) {// TODO Auto-generated method stubStudent stu new Student();stu.setName("李華");stu.setSex(Genders.MALE);stu.setAge(24);System.out.println(stu.getSex());}} pa…

HDbaseT 高清傳輸更簡單——只需一根網線

HDbaseT支持最高20Gbps的傳輸速率&#xff0c;能更好的支持未來的3D和2K4K視頻格式&#xff0c;傳輸采用普通的CAT5e/6網絡線纜&#xff0c;連接器也采用普通的 RJ45接頭&#xff0c;而傳輸距離達到了100米&#xff0c;除了提供視頻信號傳輸功能外&#xff0c;還具有網絡連接以…

2017年

2017年對自己來說這一年是最需要成長的一年&#xff0c;肩上的責任越來越大了。轉載于:https://www.cnblogs.com/jimmy1293/p/6543533.html

解決 | 此數據庫文件跟當前sql server實例不兼容 sql server2008無法連接到(local)...

最近在搞ASP.NET&#xff0c;因實驗室VS版本跟PC不一樣可能&#xff0c;拷回來一打開就這樣子&#xff1a; 眉頭一皺的我打開我的古董SQL&#xff0c;自從用了MySQL就沒碰它了我的鍋。。。果然。。連接的時候。。。不慌&#xff0c;(win 10)打開控制面板\系統和安全\管理工具 -…

IP大時代下,網絡槍機技術發展現狀

來源&#xff1a;a&s《評測&選型》 作者&#xff1a;海康威視程瑋 在視頻監控行業內&#xff0c;有很多里程碑式的產品&#xff0c;我們可以從這些產品中了解視頻監控的發展趨勢。2000年左右&#xff0c;第一臺DVR面世奠定了視頻監控行業從CCTV走向數字化的基礎&#x…

JVM調優總結(3):垃圾回收面臨的問題

如何區分垃圾 上面說到的“引用計數”法&#xff0c;通過統計控制生成對象和刪除對象時的引用數來判斷。垃圾回收程序收集計數為0的對象即可。但是這種方法無法解決循環引用。所以&#xff0c;后來實現的垃圾判斷算法中&#xff0c;都是從程序運行的根節點出發&#xff0c;遍歷…

RoHS、無鉛制程、無鹵 的基本介紹

一、RoHS是歐盟對電子電器產品不能超標含有某些有害物質的禁令&#xff1b;在具體產品生產中&#xff0c;從原材料的選擇、采購到制程中可能會污染產品&#xff08;和產品接觸&#xff09;的生產輔助材料&#xff0c;都必須不能超標含有&#xff08;有最大允許濃度&#xff09;…

springCloud分布式事務實戰(九)改造ThemeMicroService 支持分布式事務

&#xff08;1&#xff09; 添加jar <!-- springCloud 事務 關鍵點1 --><dependency><groupId>com.codingapi</groupId><artifactId>transaction-springcloud</artifactId><version>${lcn.last.version}</version><exclu…

日常的一天學習

今天的學習仍然沒有特別明確的計劃&#xff0c;也許自己不應該再徘徊&#xff0c;專心做java編程挺好的啊&#xff0c;也許還能找到不錯的工作&#xff0c;可是自己始終還是想成為一個研究安全的人&#xff0c;只是不知道自己在畢業的時候能不能成長到靠安全來養活自己。 早上主…

庖丁解牛-----Live555源碼徹底解密(根據MediaServer講解Rtsp的建立過程)

live555MediaServer.cpp服務端源碼講解(testRelay.cpp,http://blog.csdn.net/smilestone_322/article/details/18923139) int main(int argc, char** argv) { // Begin by setting up our usage environment: TaskScheduler* scheduler BasicTaskScheduler::createNew(); Usa…

運放搭建主動濾波電路

主動低通濾波電路 R1R216K R3R4100K C1C20.01uF 放大倍數AvR4/(R3R4) Freq1KHz 主動高通濾波電路 C12*C20.02uF,C20.01uF R1R2110K 6dBLow-cutFreq100Hz

deployd使用

安裝node,用npm 安裝deployd , npm install deployd -g。 cd進入文件夾&#xff0c;輸入 dpd create deploydDemo&#xff0c;然后 dpd -p 5500 deploydDemo\app.dpd&#xff08;5500是你開啟的mongodb創建的服務&#xff09;&#xff0c;接著在瀏覽器中輸入 http://localhost:…

android自定義布局實現優惠券效果

最近需要實現一個凹凸效果的擬物化優惠券效果&#xff0c;我一看&#xff0c;本來想用.9圖片做背景實現的&#xff0c;雖說圖片做背景實現省事兒方便&#xff0c;但是能用代碼實現最好不過了&#xff0c;最終我還是選擇了用代碼來實現&#xff0c;于是有了下文。 最終效果圖 de…

郵件實現詳解(四)------JavaMail 發送(帶圖片和附件)和接收郵件

好了&#xff0c;進入這個系列教程最主要的步驟了&#xff0c;前面郵件的理論知識我們都了解了&#xff0c;那么這篇博客我們將用代碼完成郵件的發送。這在實際項目中應用的非常廣泛&#xff0c;比如注冊需要發送郵件進行賬號激活&#xff0c;再比如OA項目中利用郵件進行任務提…

運放搭建電壓電流轉換電路分析

如下圖電路&#xff0c;電流可以轉換成電壓&#xff0c;電壓也可以轉換成電流&#xff1b; 根據虛斷&#xff1a;(Vi–V1)/R2 (V1–V4)/R6 &#xff08;a&#xff09; 同理 (V3–V2)/R5V2/R4 &#xff08;b&#xff09; 根據虛短&#xff1a; V1V2 &#xff08;c&#xff09…

centos7裝完chrome無法使用yum問題解決

2019獨角獸企業重金招聘Python工程師標準>>> 續前文裝好chrome后&#xff0c;yum居然用不了&#xff0c;提示錯誤“Basic XLib functionality test failed!” 呵呵。。。呵呵了.... 【題外話~個人真心覺得pythonseleniumchrome在linux環境下開發和使用 簡直蛋疼無比…

實驗二第二部分

第二部分 FTP協議分析 1. 兩個同學一組&#xff0c;A和B。 2.A同學架設FTP服務器&#xff0c;并設置用戶名和密碼&#xff0c;例如gao / gao 3.B同學在機器中安裝Wireshark&#xff0c;并將其打開&#xff1b;之后用用戶名和密碼登陸A同學的FTP服務器&#xff0c;并上傳一張圖片…

運放搭建的跟隨電路作用與分析

電壓跟隨器&#xff0c;顧名思義就是輸出電壓與輸入電壓是相同的&#xff0c;就是說電壓跟隨器的電壓放大倍數恒小于且接近1。 電壓跟隨器的顯著特點就是&#xff0c;輸入阻抗高&#xff0c;而輸出阻抗低。 根據其顯著特點&#xff0c;常見的作用如下&#xff1a; 1- 緩沖 在…

Spring Boot(十二)單元測試JUnit

一、介紹 JUnit是一款優秀的開源Java單元測試框架&#xff0c;也是目前使用率最高最流行的測試框架&#xff0c;開發工具Eclipse和IDEA對JUnit都有很好的支持&#xff0c;JUnit主要用于白盒測試和回歸測試。 白盒測試&#xff1a;把測試對象看作一個打開的盒子&#xff0c;程序…

介紹TCP/udp比較好的博客

http://blog.csdn.net/nana_93/article/details/8743525