青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++分析研究  
C++
日歷
<2014年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
統計
  • 隨筆 - 92
  • 文章 - 4
  • 評論 - 4
  • 引用 - 0

導航

常用鏈接

留言簿

隨筆檔案

文章檔案

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

 

  常遇到的動態內存回收問題

  在C++的編程過程中,我們經常需要申請一塊動態內存,然后當用完以后將其釋放。通常而言,我們的代碼是這樣的:

  1: void func()

  2: {

  3: //allocate a dynamic memory

  4: int *ptr = new int;

  5:

  6: //use ptr

  7:

  8: //release allocated memory

  9: delete ptr;

  10: ptr = NULL;

  11: }

  如果這個函數func()邏輯比較簡單,問題不大,但是當中間的代碼有可能拋出異常時,上面的代碼就會產生內存泄露(memory leak),如下面代碼中第11行和12行將不會被執行。當然有碼友會說用try-catch包起來就可以了,對,沒錯,但是代碼中到處的try-catch也挺被人詬病的SAT答案 www.sats686.com

  1: void func()

  2: {

  3: //allocate a dynamic memory

  4: int *ptr = new int;

  5:

  6: throw “error”; //just an example

  7:

  8: //use ptr

  9:

  10: //release allocated memory

  11: delete ptr;

  12: ptr = NULL;

  13: }

  而且當函數有多個返回路徑時,需要在每個return前都要調用delete去釋放資源,代碼也會變的不優雅了。

  1: void func()

  2: {

  3: //allocate a dynamic memory

  4: int *ptr = new int;

  5:

  6: if (...)

  7: {

  8: //...a

  9:

  10: //release allocated memory

  11: delete ptr;

  12: ptr = NULL;

  13: return;

  14: } else if (....)

  15: {

  16: //...b

  17:

  18: //release allocated memory

  19: delete ptr;

  20: ptr = NULL;

  21: return;

  22: }

  23:

  24: //use ptr

  25:

  26: //release allocated memory

  27: delete ptr;

  28: ptr = NULL;

  29: }

  鑒于此,我們就要想辦法利用C++的一些語言特性,在函數退棧時能夠將局部申請的動態內存自動釋放掉。熟悉C++的碼友們都知道,當一個對象退出其定義的作用域時,會自動調用它的析構函數。也就是說如果我們在函數內定義一個局部對象,在函數返回前,甚至有異常產生時,這個局部對象的析構函數都會自動調用。如果我們能夠將釋放資源的代碼交付給這個對象的析構函數,我們就可以實現資源的自動回收。這類技術,通常被稱為RAII (初始化中獲取資源)托福答案


  什么是RAII以及幾個例子

  在C++等面向對象語言中,為了管理局部資源的分配以及釋放(resource allocation and deallocation),實現異常安全(exception-safe)、避免內存泄露等問題,C++之父Bjarne Stroustrup發明了一種叫做”初始化中獲取資源“ (RAII, Resource Acquisition Is Initialization,也可以叫做Scope-Bound Resource Management)的技術。簡單來說,它的目的就是利用一個局部對象,在這個對象的構造函數內分配資源,然后在其析構函數內釋放資源。這樣,當這個局部對象退出作用域時,它所對應的的資源即可自動釋放。在實現上,它通常有三個特點:

  創建一個特殊類,在其構造函數初申請資源;

  封裝目標對象,將申請資源的目標對象作為這個特殊類的成員變量;

  在這個類的析構函數內,釋放資源。

  一個典型的例子就是標準庫中提供的模板類std::auto_ptr。如在《C++程序設計語言》(《The C++ Programming Language, Special Edition》, Bjarne Stroustrup著,裘宗燕譯)中第327頁所描述的SAT答案

  1: template

  2: class std::auto_ptr {

  3:

  4: public:

  5: //在構造函數中,獲得目標指針的管理權

  6: explicit auto_ptr(X *p = 0) throw() { ptr = p; }

  7: //在析構函數中,釋放目標指針

  8: ~auto_ptr() throw() { delete ptr; }

  9:

  10: //...

  11:

  12: //重裝*和->運算符,使auto_ptr對象像目標指針ptr一樣使用

  13: X& operator*() const throw() { return *ptr; }

  14: X* operator->() const throw() { return ptr; }

  15:

  16: //放棄對目標指針的管理權

  17: X* release() throw() { X* t = ptr; ptr = 0; return t; }

  18:

  19: private:

  20: X *ptr;

  21: };

  想要使用它,非常簡單,例如

  1: #include

  2:

  3: void func()

  4: {

  5: std::auto_ptr p(new int);

  6:

  7: //use p just like ptr

  8:

  9: return;

  10: }

  另一個例子,是利用GCC中的cleanup attribute。它可以指定一個函數,在該變量退出作用域時可以執行。例如Wikipedia上提到的宏

  1: #define RAII_VARIABLE(vartype,varname,initval,dtor) \

  2: void _dtor_ ## varname (vartype * v) { dtor(*v); } \

  3: vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)

  我們可以這樣使用,例如

  1: void example_usage() {

  2: RAII_VARIABLE(FILE*, logfile, fopen("logfile.txt", "w+"), fclose);

  3: fputs("hello logfile!", logfile);

  4: }

  還有一個例子,是在劉未鵬的博客文章”C++11 (及現代C++風格)和快速迭代式開發“中的”資源管理“一節中看到的,他借助C++11的std::function實現了這一特性。感興趣的碼友可以到他博客內閱讀。

  筆者采用的方法

  對于new/delete,使用上面提到的std::auto_ptr就可以了,但是對于new/delete[]一個動態的一維數組,甚至二維數組,auto_ptr就無能為力了。而且在一些項目中,特別是一些有著悠久歷史的代碼中,還存在著使用malloc, new混用的現象。所以筆者設計了一個auto_free_ptr類,實現目標資源的自動回收。它的實現比較簡單,只利用了RAII的第三個特點——”在類的析構函數內釋放資源”,但有一個優點是可以在申請堆內存代碼前使用托福答案

  代碼如下,

  1: //auto_free_ptr is only used for automation free memory

  2: template

  3: class auto_free_ptr

  4: {

  5: public:

  6: typedef enum {invalid, new_one, new_array, alloc_mem} EFLAG;

  7: auto_free_ptr() { initialize(); }

  8: ~auto_free_ptr(){ free_ptr(); }

  9:

  10: ///set the pointer needed to automatically free

  11: inline void set_ptr(T** new_ptr_address, EFLAG new_eflag)

  12: { free_ptr(); p_ptr = new_ptr_address; eflag = new_eflag; }

  13:

  14: ///give up auto free memory

  15: inline void give_up() { initialize(); }

  16:

  17: protected:

  18: inline void initialize() { p_ptr = NULL; eflag = invalid; }

  19: inline void free_ptr() throw()

  20: {

  21: if(!p_ptr || !(*p_ptr)) return;

  22:

  23: switch(eflag)

  24: {

  25: case alloc_mem: { free(*p_ptr), (*p_ptr) = NULL, p_ptr = NULL; break; }

  26: case new_one: { delete (*p_ptr), (*p_ptr) = NULL, p_ptr = NULL; break; }

  27: case new_array: { delete[] (*p_ptr),(*p_ptr) = NULL, p_ptr = NULL; break; }

  28: }

  29: }

  30:

  31: protected:

  32: T** p_ptr; //!< pointer to the address of the set pointer needed to automatically free

  33: EFLAG eflag; //!< the type of allocation

  34:

  35: private:

  36: DISABLE_COPY_AND_ASSIGN(auto_free_ptr);

  37: };
  為了使用方便,封裝兩個宏:

  1: // auto-free macros are mainly used to free the allocated memory by some local variables in the internal of function-body

  2: #define AUTO_FREE_ENABLE( class, ptrName, ptrType ) \

  3: auto_free_ptr auto_free_##ptrName; \

  4: auto_free_##ptrName.set_ptr(&ptrName,auto_free_ptr::ptrType)

  5:

  6: #define AUTO_FREE_DISABLE( ptrName ) auto_free_##ptrName.give_up()

  使用起來很簡單,例如

  1: void func(int nLftCnt, int nRhtCnt)

  2: {

  3: if (!nLftCnt && !nRhtCnt)

  4: return;

  5:

  6: unsigned *pLftHashs = NULL;

  7: unsigned *pRhtHashs = NULL;

  8:

  9: //在申請堆內存之前,使用auto_free_ptr

  10: AUTO_FREE_ENABLE(unsigned, pLftHashs, new_array);

  11: AUTO_FREE_ENABLE(unsigned, pRhtHashs, new_array);

  12:

  13: //....

  14:

  15: if (nLftCnt)

  16: {

  17: pLftHashs = new unsigned[nLftCnt];

  18: //...a

  19: }

  20:

  21: if (nRhtCnt)

  22: {

  23: pRhtHashs = new unsigned[nRhtCnt];

  24: //...b

  25: }

  26:

  27: //....

  28:

  29: if (...)

  30: {

  31: //因為下面這個函數可以釋放資源,所以在它前面放棄對目標指針的管理權

  32: AUTO_FREE_DISABLE(pLftHashs);

  33: AUTO_FREE_DISABLE(pRhtHashs);

  34:

  35: //這個函數可以釋放資源

  36: free_hash_arrays(pLftHashs, pRhtHashs);

  37: }

  38: }

  同樣的,有時我們需要申請一個動態二維數組,所以也實現一個對應的auto_free_2D_ptr

  1: //auto_free_2D_ptr is only used for automation free memory of 2D array

  2: template

  3: class auto_free_2D_ptr

  4: {

  5: public:

  6: typedef enum {invalid, new_one, new_array, alloc_mem} EFLAG;

  7: auto_free_2D_ptr() { initialize(); }

  8: ~auto_free_2D_ptr() { free_ptr(); }

  9:

  10: ///set the pointer needed to automatically free

  11: inline void set_ptr( T** new_ptr_address,EFLAG new_eflag, int new_length_row )

  12: { free_ptr(); p_ptr = new_ptr_address; eflag = new_eflag; length_row = new_length_row; }

  13:

  14: //give up auto free memory

  15: inline void give_up() { initialize(); }

  16:

  17: protected:

  18: inline void initialize() { p_ptr = NULL; eflag = invalid; length_row = 0;}

  19: inline void free_ptr() throw()

  20: {

  21: if(!p_ptr || !(*p_ptr)) return;

  22:

  23: for(int i = 0; i < length_row; i++)

  24: {

  25: if(!(*p_ptr)[i]) continue;

  26: switch(eflag)

  27: {

  28: case alloc_mem: { free((*p_ptr)[i]); break; }

  29: case new_one: { delete (*p_ptr)[i]; break; }

  30: case new_array: { delete[] (*p_ptr)[i]; break; }

  31: }

  32: (*p_ptr)[i] = NULL;

  33: }

  34: switch(eflag)

  35: {

  36: case alloc_mem: { free((*p_ptr)); break; }

  37: default: { delete[] (*p_ptr); break; }

  38: }

  39: (*p_ptr) = NULL, p_ptr = NULL;

  40: }

  41:

  42: protected:

  43: T** p_ptr; //!< pointer to the address of the set pointer needed to automatically free

  44: EFLAG eflag; //!< the type of allocation

  45: int length_row; //!< the row length such as ptr[length_row][length_col]

  46:

  47: private:

  48: DISABLE_COPY_AND_ASSIGN(auto_free_2D_ptr);

  49: };

  50:

  51: #define AUTO_FREE_2D_ENABLE( class, ptrName, ptrType, rowNum ) \

  52: auto_free_2D_ptr auto_free_##ptrName; \

  53: auto_free_##ptrName.set_ptr(&ptrName,auto_free_2D_ptr::ptrType, rowNum)

  54:

  55: #define AUTO_FREE_2D_DISABLE( ptrName ) AUTO_FREE_DISABLE( ptrName )

  下面是個例子

  1: void func(int row, int col)

  2: {

  3: if (!row && !col)

  4: return;

  5:

  6: int **ptr = new int*[ row ];

  7: for( int r = 0; r < row; ++r ) { ptr[r] = new int[ col ];}

  8:

  9: AUTO_FREE_2D_ENABLE( int, ptr, new_array, row );

  10:

  11: //....

  12: }

  到這里就結束了,有些碼友可能會說,何必這么麻煩,boost內有很多智能指針供選擇,用share_ptr, scoped_ptr, scoped_array,unique_ptr, auto_ptr 中的一個不就行了嗎? 沒錯!如果你正在開發的代碼中,允許用boost,并且在相關程序接口統一都用智能指針來管理、不會用到源對象指針的話,當然優先選boost,但是當你的代碼中由于歷史原因,有些接口不可變更,且new/delete, malloc/free都存在,而且依然需要使用源對象指針來完成大部分工作時,不妨試試我設計的這個閹割版的scoped_ptr/scoped_array。總之,根據自己的實際情況來選擇合適的方案,如果標準方案不適用,就自己寫一個托福答案

posted on 2014-11-16 09:05 HAOSOLA 閱讀(708) 評論(0)  編輯 收藏 引用
 
Copyright © HAOSOLA Powered by: 博客園 模板提供:滬江博客
PK10開獎 PK10開獎
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久综合色影院| 在线播放视频一区| 亚洲日本成人在线观看| 欧美激情精品久久久久久蜜臀 | 亚洲黄色成人| 午夜精品久久久久久久99热浪潮| 一区二区三区免费在线观看| 欧美jjzz| 亚洲人成久久| 亚洲一区二区在线免费观看| av成人免费| 久热综合在线亚洲精品| 亚洲第一页自拍| 久久久精彩视频| 一本色道88久久加勒比精品| 中文成人激情娱乐网| 亚洲精品国产视频| 亚洲精品欧美专区| 日韩视频久久| 久久爱91午夜羞羞| 久久久久久噜噜噜久久久精品| 麻豆精品视频在线| 久久久久久夜精品精品免费| 亚洲精品一区二区三区福利| 中文av一区特黄| 最新国产乱人伦偷精品免费网站 | 一区二区三区四区五区视频 | 久久先锋影音| 欧美日韩高清在线| 国产真实久久| 亚洲少妇一区| 乱人伦精品视频在线观看| 亚洲看片一区| 久久久久久自在自线| 欧美亚一区二区| 亚洲国内欧美| 久久精品国产一区二区电影| 欧美在线影院| 亚洲国产精品一区二区三区| 玖玖玖国产精品| 亚洲图片欧美日产| 久久精品国产77777蜜臀| 欧美日韩亚洲一区在线观看| 国产精品色一区二区三区| 亚洲欧洲一区二区在线观看| 亚洲一区二区三区激情| 久久精品亚洲一区二区三区浴池| 欧美成人激情在线| 午夜亚洲视频| 欧美日韩99| 影音先锋亚洲一区| 亚洲欧美国产精品桃花| 欧美色偷偷大香| 激情综合色综合久久综合| 99国内精品| 在线观看欧美日本| 欧美一区二区三区免费视| 亚洲第一色在线| 午夜精品久久久久久久99樱桃| 欧美日韩视频| 亚洲国产精品嫩草影院| 久久gogo国模啪啪人体图| 久久久av毛片精品| 亚洲欧美日韩在线观看a三区| 牛人盗摄一区二区三区视频| 国产香蕉97碰碰久久人人| 伊人久久大香线蕉综合热线| 久久久综合精品| 亚洲一级电影| 欧美日韩伦理在线| 国产一区二区三区久久悠悠色av | 欧美一区日韩一区| 亚洲精品日韩欧美| 麻豆精品在线视频| 亚洲日本黄色| 欧美激情成人在线视频| 久久精品国产免费看久久精品| 国产精品久久久久久久久久久久久久 | 在线免费观看日本一区| 午夜精品免费| 亚洲美女色禁图| 国产精品av一区二区| 亚洲网址在线| 亚洲六月丁香色婷婷综合久久| 午夜精品一区二区在线观看| 激情伊人五月天久久综合| 久久久91精品国产| 校园春色国产精品| 国产一区二区三区久久| 欧美成人综合在线| 免费国产一区二区| 日韩亚洲视频在线| 午夜老司机精品| 亚洲欧洲一区二区三区| 日韩亚洲精品视频| 国产欧美一区二区三区另类精品 | 欧美色图麻豆| 久久国产精品久久精品国产| 亚洲欧美日韩一区二区三区在线观看| 国产精品网站在线观看| 黑人巨大精品欧美黑白配亚洲| 久久精品日产第一区二区| 欧美一区午夜精品| 亚洲国产精品一区二区久| 亚洲无限av看| 久久久国产一区二区三区| 精品av久久707| 日韩视频免费大全中文字幕| 国产综合色一区二区三区| 欧美成人精品福利| 欧美日韩在线免费视频| 国产麻豆午夜三级精品| 亚洲高清不卡av| 欧美视频免费看| 久久久久国产成人精品亚洲午夜| 欧美国产一区二区| 久久男人av资源网站| 国产精品久久久久国产精品日日| 欧美国产综合视频| 国产视频在线观看一区二区三区| 亚洲日本欧美日韩高观看| 国内外成人免费激情在线视频网站 | 欧美乱大交xxxxx| 久久永久免费| 国产欧美日韩精品丝袜高跟鞋| 亚洲激情在线播放| 亚洲成人中文| 久久精彩视频| 欧美中文在线字幕| 国产精品久久久久99| 亚洲狼人综合| av成人免费在线观看| 免费成人在线观看视频| 久久午夜羞羞影院免费观看| 国产精品亚洲成人| 中文高清一区| 亚洲欧美另类中文字幕| 欧美视频中文一区二区三区在线观看 | 久热综合在线亚洲精品| 国语自产在线不卡| 久久国产成人| 欧美成人黄色小视频| 91久久午夜| 亚洲欧美在线另类| 欧美一级视频精品观看| 国产精品一区二区在线| 亚洲四色影视在线观看| 亚洲永久免费精品| 欧美日韩在线播放三区四区| 亚洲级视频在线观看免费1级| 亚洲三级电影全部在线观看高清| 久久在线精品| 亚洲国产裸拍裸体视频在线观看乱了| 美女性感视频久久久| 免费亚洲视频| 亚洲精品国精品久久99热一| 欧美精品国产一区二区| 亚洲欧洲精品一区二区三区 | 亚洲福利免费| 亚洲肉体裸体xxxx137| 欧美日韩午夜视频在线观看| 在线视频亚洲欧美| 国产精品不卡在线| 亚洲午夜视频在线| 亚洲欧美资源在线| 国产日产欧产精品推荐色| 久久成人羞羞网站| 亚洲激情国产| 欧美日韩国产91| 亚洲一区二区成人在线观看| 久久久激情视频| 99精品国产在热久久下载| 欧美视频在线一区| 久久先锋资源| 亚洲一区二区三区中文字幕在线| 久久成人免费电影| 亚洲精品中文字幕在线观看| 国产精品美女久久福利网站| 久久久精品国产免大香伊| 日韩视频免费| 国产欧美一级| 欧美日韩国产综合网| 亚洲嫩草精品久久| 亚洲国产裸拍裸体视频在线观看乱了中文 | 欧美**字幕| 亚洲一区影院| 国产一区日韩二区欧美三区| 欧美黑人在线播放| 亚洲综合色婷婷| 欧美成人精品不卡视频在线观看| 亚洲欧美日韩国产综合在线| 91久久精品国产91久久性色| 国产精品区一区| 欧美伦理在线观看| 欧美一级久久久| 亚洲婷婷综合色高清在线 | 久久综合久久美利坚合众国| 99天天综合性| 国产一区二区三区最好精华液| 欧美激情一二三区|