自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊智能指針和所有權的問題

開發(fā) 后端
在編程語言中,對堆對象的內存管理是一個麻煩又復雜的問題。一不小心就會帶來問題,本文簡單探討一下關于對象所有權的問題。

[[414238]]

在編程語言中,對堆對象的內存管理是一個麻煩又復雜的問題。一不小心就會帶來問題,比如JS里一直引用一個已經不使用的對象導致gc無法回收,或者C++里多個變量指向同一塊內存導致重復釋放。本文簡單探討一下關于對象所有權的問題。

對象的所有權意味著當我們分配一個對象的時候,誰持有這個對象的所有權,比如下面代碼。

  1. Object *obj = new Object(); 

那么obj就持有了對象的所有權。但是現實往往比較復雜,比如我們看看下面代碼。

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

執(zhí)行上面的代碼,我們在test函數里分配一個堆對象,執(zhí)行完test后我們發(fā)現Demo對象的析構函數并沒有執(zhí)行,這就造成了內存泄漏。那我們需要怎么做呢?我們需要收到釋放對象對應的內存。修改一下test函數的代碼。

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

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

  1. #include <iostream> 
  2.  
  3. #include<stdio.h> 
  4.  
  5.  
  6.  
  7. using namespace std; 
  8.  
  9.  
  10.  
  11. class Demo { 
  12.     public
  13.     ~Demo(){ 
  14.         printf("執(zhí)行析構函數"); 
  15.     } 
  16.  
  17. }; 
  18.  
  19.  
  20. template<class T> 
  21. class SmartPoint 
  22.     T* point; 
  23. public
  24.     SmartPoint(T *ptr = nullptr) :point(ptr) {} 
  25.  
  26.     ~SmartPoint() { 
  27.         if (point) { 
  28.             // 會調用point指向對象的的析構函數 
  29.             delete point; 
  30.         } 
  31.     } 
  32.     // 使用智能指針就像使用內部包裹的的對象一樣 
  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<Demo> p(new Demo()); 
  48.  
  49.  
  50.  
  51.  
  52. int main(){ 
  53.  
  54.    test(); 
  55.    return 0; 
  56.  

智能指針的原理比較簡單,因為智能指針對象是在棧上面分配的,離開作用域的時候會被自動釋放,然后在智能指針的析構函數里釋放包裹的內部對象。看起來是很完美的解決方案。但是智能指針也帶來了一些問題,那就是在復制或賦值的時候。我們看看代碼。

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

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

  1. #include <iostream> 
  2.  
  3. #include<stdio.h> 
  4.  
  5.  
  6.  
  7. using namespace std; 
  8.  
  9.  
  10.  
  11. class Demo { 
  12.     public
  13.     ~Demo(){ 
  14.         printf("執(zhí)行析構函數"); 
  15.     } 
  16.  
  17. }; 
  18.  
  19.  
  20. template<class T> 
  21. class SmartPoint 
  22.     T* point; 
  23. public
  24.     SmartPoint(T *ptr = nullptr) :point(ptr) {} 
  25.     // 實現復制構造函數 
  26.     SmartPoint(SmartPoint & p) {  
  27.         // 指向p.point對應的內存 
  28.         point = p.point; 
  29.         // p.point置null 
  30.         p.point = nullptr; 
  31.     } 
  32.     ~SmartPoint() { 
  33.         if (point) { 
  34.             // 會調用point指向對象的的析構函數 
  35.             delete point; 
  36.         } 
  37.     } 
  38.     // 使用智能指針就像使用內部包裹的的對象一樣 
  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<Demo> p(new Demo()); 
  54.    SmartPoint<Demo> p2 = p; 
  55.    return 0; 
  56.  

我們實現了一個復制構造函數,在main里執(zhí)行p2=p時會被執(zhí)行,在復制構造函數中,我們實現了所有權轉移,這時候p2時Demo對象的持有者,而p指向null,這時候不能再對p進行操作。這時候我們可以在SmartPoint中實現一個isNull函數用于判斷智能指針的有效性。

  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.     // 所有權轉移 
  6.     let _box2 = _box1; 
  7.     // 報錯 
  8.     println!("{}", _box1.0); 
  9.  

 編譯上面代碼會報錯,是編譯而不是運行,這就是Rust,在編譯期就解決了這個問題。Box是智能指針,以上代碼和剛才C++中的代碼類似,當執(zhí)行_box2=_box1的時候,堆對象的所有權就轉移到了_box2,_box1相當于包裹了一個空指針,而Rust不允許你再訪問_box1管理里的內存。

 

責任編輯:姜華 來源: 編程雜技
相關推薦

2011-01-07 09:19:35

Linux文件權限

2024-03-19 14:43:55

Rust編譯所有權

2024-09-02 10:40:18

2017-07-27 13:34:52

Rust所有權數據

2022-11-03 15:14:43

Linux文件權限

2022-03-18 08:00:00

區(qū)塊鏈代幣以太坊

2009-11-28 20:21:14

2023-10-10 11:04:11

Rust難點內存

2011-01-20 07:50:51

Linux文件系統(tǒng)管理所有權

2024-01-10 09:26:52

Rust所有權編程

2011-03-03 15:40:55

PureFTPd

2013-08-16 10:46:20

2022-05-30 00:19:13

元宇宙NFTWeb3

2015-07-27 11:34:03

Linux內核指針

2022-08-11 10:42:58

Rust

2018-01-23 11:15:28

云計算數據平臺云平臺

2018-12-14 10:08:23

物聯網訂閱IOT

2021-08-11 09:01:48

智能指針Box

2017-10-23 12:42:42

2009-09-12 09:46:47

Windows 7所有權添加
點贊
收藏

51CTO技術棧公眾號