1、高质量 C+编程点滴有效解决内存泄露一、你需要一个函数将一个数组赋值为等差数列,并将会在函数的外部使用它。不合理:int *GetArray( int n )int *p = new intn;for ( int i = 0; i n; i+ )pi = i;return p;合理:void GetArray( int *p, int n )for ( int i = 0; i n; i+ )pi = i;解析:检查内存泄露的最好办法,就是检查完全配对的申请和释放,在函数中申请而在外部释放,将导致代码的一致性变差,难以维护。而且,你写的函数不一定是你自己使用的,这样的函数别人会不知道该怎么适当
2、的使用,如果它是一个DLL 的导出函数,并且你在不同的平台下使用了,便会导致系统崩溃。最好的解决办法就是在函数调用的外面将内存申请好,函数只对数据进行复制。二、你需要写一个类来为你管理一个指针,这个类将封装对指针的申请内存、释放和其它一些基本操作。不合理:class Apublic:A( void ) A( void ) delete m_pPtr; void Create( int n ) m_pPtr = new intn; private:int *m_pPtr;合理:class Apublic:A( void ) : m_pPtr(0)A( void ) Clear(); bool C
3、reate( int n ) if ( m_pPtr ) return false; m_pPtr = new intn; return ture; void Clear( void ) delete m_pPtr; m_pPtr = 0; private:int *m_pPtr;解析:不合理的代码就在于当你重复调用 Create 的时候就会造成内存泄露,解决的办法就是在 new 之前判断一下指针是否为 0。要能够有效的执行这个判断,则必须在构造的时候对指针进行初始化,并为这个类添加一个 Clear 函数来释放内存。三、接上题的 Create 函数,你现在需要根据传入的参数做一些比较复杂的算法
4、操作,并对申请的数组赋值。不合理:bool Create(int *a, int n )if ( m_pPtr )return false;m_pPtr = new intn;for ( int i = 0; i n; i+ )m_pPtri = 3 / ai;return true;合理:templateclass auto_arraypublic:explicit auto_array(_Ty *pPtr=0)throw():m_Ptr(pPtr)auto_array()deletem_Ptr;void reset(_Ty *pPtr=0)if(pPtr!=m_Ptr)deletem_Pt
5、r;m_Ptr=pPtr;_Ty* release(void)_Ty *pTemp=m_Ptr;m_Ptr=0;return pTemp;private:auto_array(const auto_array;bool A:Create(int *a, int n )if ( m_pPtr )return false;auto_array PtrGuard( new intn );for ( int i = 0; i n; i+ )if ( 0 = ai )return false;PtrGuard .get()i = 3 / ai;m_pPtr = PtrGuard.release();re
6、turn true;解析:在循环中,当参数数组 a 中的某一个值为 0 时,将会产生除 0 异常,那么,这将会导致你在上面为 m_pPtr 申请的内存不能合理的释放。为了解决这个问题,我们写了一个 auto_array 作为卫兵来看守企图逃逸的指针。在 auto_array对象 PtrGuard 析构的时候它会同时删除附加在它身上的内存指针。我们首先用 PtrGuard 来进行所有的指针操作,在确定操作完全结束的最后,把指针再赋给真正的变量,并使 PtrGuard 放弃对该指针的附加,这样我们就得到了一个最安全的结果。另外需要注意的是,C+的 STL 库里本来有一个和 auto_array 功
7、能非常相似的模版类 auto_ptr,但是它只支持单个对象的内存,不支持数组,写这样一个 auto_array 也是不得已而为之。使用合理的内存访问方式一、你需要开辟一段内存来存放和管理一个 4 x 4 的矩阵,并单位化之。不合理:int aMatrix44;for ( int i = 0; i 4; i+ )for ( int j = 0; j 4; j+ )if ( i = j )aMatrixij = 1;elseaMatrix ij = 0;合理:int aMatrix4 * 4;for ( int i = 0; i 4; i+ )for ( int j = 0; j 4; j+ )i
8、f ( i = j )aMatrix i * 4 + j = 1;elseaMatrix i * 4 + j = 0;解析:在任何时候都要避免使用多维数组,数组维数的增加,相应的程序复杂度将会以几何级数的方式增加,也更加的难于理解。二、你需要对上面那个矩阵赋值,使它从左上角向右下角按先纵后横的顺序给它赋值不合理:for( int i = 0; i 4; i+ )for ( int j = 0; j 4; j+ )aMatrix j * 4 + i = i * 4 + j;合理:for( int i = 0; i 4; i+ )for ( int j = 0; j 4; j+ )aMatrixi
9、 * 4 + j = j * 4 + i;解析:尽量保证顺序的访问数组的每一个元素。由于 Windows 内存的管理模式,内存是分页管理的。顺序访问数组可以基本保证页面不会来回切换,从而减少了页失效的数量,提高了程序的整体性能。这种性能的提升对于大的数组尤为明显。三、你需要用 3 个 float 值来表示一个三维的点,并要写一个函数对一个三维点的数组进行计算赋值。不合理:void foo( float *pPoints3 )float aPoint3 = 1.0f, 2.0f, 3.0f ;int nCount = (int)_msize( pPoints );for ( int i = 0;
10、 i nCount; i+ )pPointsi0 = aPoint0;pPointsi1 = aPoint1;pPointsi2 = aPoint2;合理:struct POINT3float x, y, z;void foo( POINT3 *pPoints, int nCount )POINT3 Pt = 1.0f, 2.0f, 3.0f ;for ( int i = 0; i nCount; i+ )pPointsi = Pt;解析:有两点,一,不要使用_msize 对数组的大小进行测定,_msize 只能对使用 malloc 或 calloc 申请的内存进行大小测定,对于其它的如 ne
11、w 或一些 API,将会导致程序的崩溃。在设计此类需要传入数组的函数时,别忘了把数组的元素数量也做为参数一并传入,哪怕它是固定的,这将是一个良好的习惯。二,对于float3这种类型,尽量避免直接使用它,最好的办法就是用 struct 对其进行简单的封装,在复制的时候直接使用“=”就可以进行准确的按位赋值了。四、你有一个函数的定义,在这个函数中会 new 一个比较大的对象 Data,并在计算后将它删除。但这个函数将被频繁调用。不合理:void foo( void )Data *p = new Data;CalcData( p );delete p;合理:char Bufsizeof(DATA);void foo( void )Data *p = new(Buf) Data;CalcData( p );解析:new(buf) type;是定位的 new 语法,它不会真正的分配内存,而是简单的在指定的已分配的内存起点上划分出一段与类型大小匹配的空间,并直接在这段内存上对该类型进行构造对象,并返回对象的指针。由于它没有真正的分配内存空间,因此它的效率是非常高的,在类似于上述例程中,频繁申请和释放一个大对象的操作,定位的 new 可以带来很大的效率提升。