信息发布软件,b2b软件,广告发布软件

标题: C++回收内存让程序再也不会无缘无故的消失在电脑上 [打印本页]

作者: 群发软件    时间: 2017-6-27 22:21
标题: C++回收内存让程序再也不会无缘无故的消失在电脑上
嵌套类分配回收内存:
  #include <stdio.h>
  #include <assert.h>
  class CA
  {
  public:
  inline static CA *GetInstance(void)
  {
  assert(m_instance != NULL);
  return m_instance;
  }
  void Print(void)
  {
  puts("主类的Print函数运行看看");
  }
  class Garbage//用来分配内存的嵌套类
  {
  public:
  Garbage(int i, int j)
  {
  printf("Garbage分配内存开始:%d %d\n", i, j);
  m_instance = new CA(123123, 234234234);
  }
  ~Garbage()
  {
  delete m_instance;
  puts("Garbage收拾残局结束");
  }
  };
  static Garbage m_garbage;
  protected:
  friend class Garbage;
  CA(int i, int j){printf("主类构造函数运行: %d %d\n", i, j);}
  ~CA(){printf("主类析构函数运行,结束了哦\n");}
  static CA *m_instance;
  };
  CA *CA::m_instance = NULL;
  CA::Garbage CA::m_garbage(2, 3);
  int main()
  {
  CA *cmb = CA::GetInstance();
  cmb->Print();
  return 0;
  }

c语言提供内存的动态分配的函数有:
malloc,calloc,realloc。在使用这些函数时,必须包含其头文件,分别为:<malloc.h>,<stdlib.h>,<alloc.h>
1.malloc函数
malloc函数原型: void *malloc(unsigned int size)
作用:在内存的动态分配区域中分配一个长度为size的连续空间。
类型说明符:void说明该函数适用与任意的数据类型。
参数:size为无符号整型数。
返回值:如果分配成功,则返回所分配内存空间的首地址。如果失败,则返回NULL。
注:申请的内存不会进行初始化。
例子:
char *p = (char *)malloc(sizeof(char)*10);
//申请了10个char长度的空间,但并不知道是否申请成功。if(NULL  == p)
{
     return;//申请内存空间失败
}
2.calloc函数
calloc函数原型:void *calloc(unsigned int num,unsigned int size)
作用:按照所给的数据个数和数据类型所占字节数,分配一个num*size连续的空间。
类型说明符:void说明该函数适用与任意的数据类型。
参数:num:无符号整数,表示要分配的个数。size:无符号整型数,表示该数据类型所占字节数。
返回值:如果分配成功,则返回内存空间的首地址,如果失败,则返回NULL。
与malloc函数区别:
     calloc申请完内存空间后,会自动初始化内存空间为0。但是malloc不会进行初始化,起内存空间存储的是一些随机数据。
例子:
char *p = (char *)calloc(10,sizeof(char));
//申请了10个char长度的内存空间
if(NULL  == p)
{
     return;//申请内存空间失败
}
3.realloc函数
realloc函数原型:void *realloc(void *ptr,unsigned int size)
作用:动态分配一个长度为size的内存空间,并把该内存空间的首地址赋值给ptr。把ptr所指的内存空间大小调整为size。
参数:ptr:指向一个内存空间的指针。size:需要的申请的内存空间大小。
返回值:如果分配成功,则返回内存空间的首地址,如果失败,则返回NULL。
注意:
例子: C++回收内存让程序再也不会无缘无故的消失在电脑上 b2b软件
C++回收内存让程序再也不会无缘无故的消失在电脑上 b2b软件
char *p = (char *)malloc(10);
//char *p = "12345";如果使用此语句,执行realloc时会发生错误char *q = p;p = (char *)realloc(p,100);//如果在p原来指向的内存后面没有足够的内存空间来扩展,那么先前分配的10个字节的内存空间被丢弃,即q指针变成了野指针
p[0] = '0';
p = (char *)realloc(p,0);
cout<<p[0]<<endl;//此语句运行时会产生错误:非法访问内存。 C++回收内存让程序再也不会无缘无故的消失在电脑上 b2b软件

C++回收内存让程序再也不会无缘无故的消失在电脑上 b2b软件


在使用c语言提供的这些动态内存分配函数后,对于这些已经申请的内存空间需要你自己进行释放。如果你没有释放,并且你只是随便运行一下自己的一个很小的程序,可能不会产生什么很大的影响。但是,如果这样一个大型程序或软件运行中调用了这些语句,而没有对申请的内存进行释放,那么后果是很严重的。
因此,在我们平时写程序的过程中,应该养成好的变成习惯。在使用了这些函数动态分配了一段内存后,要记得对其进行释放。
释放的函数为free函数:
free函数原型为:void free(void *ptr)
作用:释放由上面3种函数所申请的内存空间。
参数:ptr:指向需要释放的内存空间的首地址。
例子:
C++回收内存让程序再也不会无缘无故的消失在电脑上 b2b软件
char *p = (char *)calloc(10,sizeof(char));
//申请了10个char长度的内存空间
if(NULL  == p)
{
     return;//申请内存空间失败
}
...
free(ptr);//释放申请的内存空间 C++回收内存让程序再也不会无缘无故的消失在电脑上 b2b软件

常遇到的动态内存回收问题
在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也挺被人诟病的:
   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页所描述的。
   1: template<class X>   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 <memory>   2:     3: void func()   4: {   5:     std::auto_ptr<int> 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<class T>   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<class> auto_free_##ptrName; \   4:     auto_free_##ptrName.set_ptr(&ptrName,auto_free_ptr<class>::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<class T>   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)) continue;  26:             switch(eflag)  27:             {  28:             case alloc_mem:  { free((*p_ptr));    break; }  29:             case new_one:    { delete (*p_ptr);   break; }  30:             case new_array:  { delete[] (*p_ptr); break; }  31:             }  32:             (*p_ptr) = 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<class> auto_free_##ptrName; \  53:     auto_free_##ptrName.set_ptr(&ptrName,auto_free_2D_ptr<class>::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。总之,根据自己的实际情况来选择合适的方案,如果标准方案不适用,就自己写一个。
如果码友有更好的实现方式或者发现什么问题,还请批评指正。

作者: niyaoz1    时间: 2017-7-2 03:08
,第一次买很满意,服务态度很好
作者: c19900420    时间: 2017-7-5 02:15
高大上了,服务很周到,能达到我想要的效果,设计后生意越来越好了!好开心啊!
作者: feiyang2006    时间: 2017-7-6 15:32
家很给力,自己不是很懂卖家马上给处理咯。给力给力
作者: jiandao1    时间: 2017-7-6 22:09
,老板人真心不错,给我便宜了许多
作者: weipinzongmeng    时间: 2017-7-13 06:55
,大爱,喜欢,是我想要的,不错,值得购买,
作者: ziyang701    时间: 2017-7-13 08:35
我抢、我抢、我抢沙发~
作者: brt02    时间: 2017-7-18 19:00
7一直很耐心解决问题。
作者: ekmci    时间: 2017-7-19 08:08
强大,使用简单便捷,真心的不错,卖家发货速度快,赞。
作者: 大宝罗滴滴    时间: 2017-7-22 20:12
心的帮助设置模板,非常满意!
作者: niyaoz1    时间: 2017-7-24 22:10
平台还不错哟,而且技术人员态度很好,很多方面都站在客户的方面着想。非常愉快的合作。
作者: jiandao1    时间: 2017-7-25 12:32
!设计人员专业!来回改动无数次,都全力配合更改!
作者: cd0010    时间: 2017-7-26 14:23
功能真好,太棒了
作者: tian001    时间: 2017-7-27 00:45
,整体满意,好评




欢迎光临 信息发布软件,b2b软件,广告发布软件 (http://postbbs.com/) Powered by Discuz! X3.2