日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
聊聊智能指針和所有權(quán)的問(wèn)題

在編程語(yǔ)言中,對(duì)堆對(duì)象的內(nèi)存管理是一個(gè)麻煩又復(fù)雜的問(wèn)題。一不小心就會(huì)帶來(lái)問(wèn)題,比如JS里一直引用一個(gè)已經(jīng)不使用的對(duì)象導(dǎo)致gc無(wú)法回收,或者C++里多個(gè)變量指向同一塊內(nèi)存導(dǎo)致重復(fù)釋放。本文簡(jiǎn)單探討一下關(guān)于對(duì)象所有權(quán)的問(wèn)題。

創(chuàng)新互聯(lián)長(zhǎng)期為1000+客戶(hù)提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為隨州企業(yè)提供專(zhuān)業(yè)的網(wǎng)站制作、成都做網(wǎng)站,隨州網(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

對(duì)象的所有權(quán)意味著當(dāng)我們分配一個(gè)對(duì)象的時(shí)候,誰(shuí)持有這個(gè)對(duì)象的所有權(quán),比如下面代碼。

 
 
 
  1. Object *obj = new Object(); 

那么obj就持有了對(duì)象的所有權(quán)。但是現(xiàn)實(shí)往往比較復(fù)雜,比如我們看看下面代碼。

 
 
 
  1. #include 
  2. using namespace std; 
  3.  
  4.  
  5.  
  6. class Demo { 
  7.     public: 
  8.     ~Demo(){ 
  9.         printf("執(zhí)行析構(gòu)函數(shù)"); 
  10.     }};void test() { 
  11.     Demo *d = new Demo(); 
  12.  
  13.  
  14.  
  15.  
  16. int main(){ 
  17.  
  18.    test(); 
  19.    return 0; 
  20.  

執(zhí)行上面的代碼,我們?cè)趖est函數(shù)里分配一個(gè)堆對(duì)象,執(zhí)行完test后我們發(fā)現(xiàn)Demo對(duì)象的析構(gòu)函數(shù)并沒(méi)有執(zhí)行,這就造成了內(nèi)存泄漏。那我們需要怎么做呢?我們需要收到釋放對(duì)象對(duì)應(yīng)的內(nèi)存。修改一下test函數(shù)的代碼。

 
 
 
  1. void test() { 
  2.     Demo *d = new Demo(); 
  3.     delete d; 
  4.  

這時(shí)候我們發(fā)現(xiàn)就會(huì)輸出執(zhí)行析構(gòu)函數(shù)幾個(gè)字了,說(shuō)明析構(gòu)函數(shù)被執(zhí)行,對(duì)象的內(nèi)存也被釋放了。手動(dòng)管理內(nèi)存不僅麻煩,而且往往容易出錯(cuò),比如我們往往會(huì)忘了釋放,尤其是代碼邏輯復(fù)雜的時(shí)候。這時(shí)候,我們可以使用智能指針解決這個(gè)問(wèn)題。

 
 
 
  1. #include  
  2.  
  3. #include 
  4.  
  5.  
  6.  
  7. using namespace std; 
  8.  
  9.  
  10.  
  11. class Demo { 
  12.     public: 
  13.     ~Demo(){ 
  14.         printf("執(zhí)行析構(gòu)函數(shù)"); 
  15.     } 
  16.  
  17. }; 
  18.  
  19.  
  20. template 
  21. class SmartPoint 
  22.     T* point; 
  23. public: 
  24.     SmartPoint(T *ptr = nullptr) :point(ptr) {} 
  25.  
  26.     ~SmartPoint() { 
  27.         if (point) { 
  28.             // 會(huì)調(diào)用point指向?qū)ο蟮牡奈鰳?gòu)函數(shù) 
  29.             delete point; 
  30.         } 
  31.     } 
  32.     // 使用智能指針就像使用內(nèi)部包裹的的對(duì)象一樣 
  33.     T& operator*() {  
  34.         return *point;  
  35.     } 
  36.  
  37.     T* operator->() {  
  38.         return point;  
  39.     } 
  40.  
  41. }; 
  42.  
  43.  
  44.  
  45. void test() { 
  46.  
  47.     SmartPoint p(new Demo()); 
  48.  
  49.  
  50.  
  51.  
  52. int main(){ 
  53.  
  54.    test(); 
  55.    return 0; 
  56.  

智能指針的原理比較簡(jiǎn)單,因?yàn)橹悄苤羔槍?duì)象是在棧上面分配的,離開(kāi)作用域的時(shí)候會(huì)被自動(dòng)釋放,然后在智能指針的析構(gòu)函數(shù)里釋放包裹的內(nèi)部對(duì)象。看起來(lái)是很完美的解決方案。但是智能指針也帶來(lái)了一些問(wèn)題,那就是在復(fù)制或賦值的時(shí)候。我們看看代碼。

 
 
 
  1. int main(){ 
  2.    SmartPoint p(new Demo()); 
  3.    SmartPoint p2 = p; 
  4.    return 0; 
  5.  

執(zhí)行下面代碼會(huì)導(dǎo)致core dump,為什么呢?我們來(lái)看看這個(gè)過(guò)程。當(dāng)執(zhí)行p2=p的時(shí)候會(huì)導(dǎo)致p2和p的內(nèi)部指針point都指向了Demo對(duì)象的地址,最后代碼執(zhí)行完畢后,兩個(gè)智能指針都執(zhí)行了釋放內(nèi)存的操作,重復(fù)釋放內(nèi)存導(dǎo)致了core dump。那如何解決這個(gè)問(wèn)題呢?一種方式是復(fù)制一份point指向的內(nèi)存,但是我們可能不知道這個(gè)內(nèi)存多大,無(wú)法復(fù)制,另一種方式就是所有權(quán)轉(zhuǎn)移。我們繼續(xù)看代碼。

 
 
 
  1. #include  
  2.  
  3. #include 
  4.  
  5.  
  6.  
  7. using namespace std; 
  8.  
  9.  
  10.  
  11. class Demo { 
  12.     public: 
  13.     ~Demo(){ 
  14.         printf("執(zhí)行析構(gòu)函數(shù)"); 
  15.     } 
  16.  
  17. }; 
  18.  
  19.  
  20. template 
  21. class SmartPoint 
  22.     T* point; 
  23. public: 
  24.     SmartPoint(T *ptr = nullptr) :point(ptr) {} 
  25.     // 實(shí)現(xiàn)復(fù)制構(gòu)造函數(shù) 
  26.     SmartPoint(SmartPoint & p) {  
  27.         // 指向p.point對(duì)應(yīng)的內(nèi)存 
  28.         point = p.point; 
  29.         // p.point置null 
  30.         p.point = nullptr; 
  31.     } 
  32.     ~SmartPoint() { 
  33.         if (point) { 
  34.             // 會(huì)調(diào)用point指向?qū)ο蟮牡奈鰳?gòu)函數(shù) 
  35.             delete point; 
  36.         } 
  37.     } 
  38.     // 使用智能指針就像使用內(nèi)部包裹的的對(duì)象一樣 
  39.     T& operator*() {  
  40.         return *point;  
  41.     } 
  42.  
  43.     T* operator->() {  
  44.         return point;  
  45.     } 
  46.  
  47. }; 
  48.  
  49.  
  50.  
  51. int main(){ 
  52.  
  53.    SmartPoint p(new Demo()); 
  54.    SmartPoint p2 = p; 
  55.    return 0; 
  56.  

我們實(shí)現(xiàn)了一個(gè)復(fù)制構(gòu)造函數(shù),在main里執(zhí)行p2=p時(shí)會(huì)被執(zhí)行,在復(fù)制構(gòu)造函數(shù)中,我們實(shí)現(xiàn)了所有權(quán)轉(zhuǎn)移,這時(shí)候p2時(shí)Demo對(duì)象的持有者,而p指向null,這時(shí)候不能再對(duì)p進(jìn)行操作。這時(shí)候我們可以在SmartPoint中實(shí)現(xiàn)一個(gè)isNull函數(shù)用于判斷智能指針的有效性。

 
 
 
  1. bool isNull() { 
  2.     return point == nullptr;  

然后在使用的地方加一下判斷。

 
 
 
  1. if (p.isNull()) { 
  2.     //  
  3.  

這顯然很麻煩。我們看看Rust怎么做。

 
 
 
  1. struct Demo(u32); 
  2.  
  3. fn main() { 
  4.     let _box1 = Box::new(Demo(1)); 
  5.     // 所有權(quán)轉(zhuǎn)移 
  6.     let _box2 = _box1; 
  7.     // 報(bào)錯(cuò) 
  8.     println!("{}", _box1.0); 
  9.  

 編譯上面代碼會(huì)報(bào)錯(cuò),是編譯而不是運(yùn)行,這就是Rust,在編譯期就解決了這個(gè)問(wèn)題。Box是智能指針,以上代碼和剛才C++中的代碼類(lèi)似,當(dāng)執(zhí)行_box2=_box1的時(shí)候,堆對(duì)象的所有權(quán)就轉(zhuǎn)移到了_box2,_box1相當(dāng)于包裹了一個(gè)空指針,而Rust不允許你再訪問(wèn)_box1管理里的內(nèi)存。


當(dāng)前題目:聊聊智能指針和所有權(quán)的問(wèn)題
文章URL:http://www.dlmjj.cn/article/cddpiic.html