高质量C++编程点滴(二)
使用合理的内存访问方式
一、你需要开辟一段内存来存放和管理一个4 x 4的矩阵,并单位化之。
不合理:
int aMatrix[4][4];
for ( int i = 0; i < 4; i++ )
{
for ( int j = 0; j < 4; j++ )
{
if ( i == j )
{
aMatrix[i][j] = 1;
}
else
{
aMatrix [i][j] = 0;
}
}
}
合理:
int aMatrix[4 * 4];
for ( int i = 0; i < 4; i++ )
{
for ( int j = 0; j < 4; j++ )
{
if ( i == j )
{
aMatrix[ i * 4 + j ] = 1;
}
else
{
aMatrix [ 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++ )
{
aMatrix[i * 4 + j ] = j * 4 + i;
}
}
解析:
尽量保证顺序的访问数组的每一个元素。由于Windows内存的管理模式,内存是分页管理的。顺序访问数组可以基本保证页面不会来回切换,从而减少了页失效的数量,提高了程序的整体性能。这种性能的提升对于大的数组尤为明显。
三、你需要用3个float值来表示一个三维的点,并要写一个函数对一个三维点的数组进行计算赋值。
不合理:
void foo( float *pPoints[3] )
{
float aPoint[3] = { 1.0f, 2.0f, 3.0f };
int nCount = (int)_msize( pPoints );
for ( int i = 0; i < nCount; i++ )
{
pPoints[i][0] = aPoint[0];
pPoints[i][1] = aPoint[1];
pPoints[i][2] = aPoint[2];
}
}
合理:
struct POINT3
{
float x, y, z;
};
void foo( POINT3 *pPoints, int nCount )
{
POINT3 Pt = { 1.0f, 2.0f, 3.0f };
for ( int i = 0; i < nCount; i++ )
{
pPoints[i] = Pt;
}
}
解析:
有两点,一,不要使用_msize对数组的大小进行测定,_msize只能对使用malloc或calloc申请的内存进行大小测定,对于其它的如new或一些API,将会导致程序的崩溃。在设计此类需要传入数组的函数时,别忘了把数组的元素数量也做为参数一并传入,哪怕它是固定的,这将是一个良好的习惯。二,对于float[3]这种类型,尽量避免直接使用它,最好的办法就是用struct对其进行简单的封装,在复制的时候直接使用“=”就可以进行准确的按位赋值了。
四、你有一个函数的定义,在这个函数中会new一个比较大的对象Data,并在计算后将它删除。但这个函数将被频繁调用。
不合理:
void foo( void )
{
Data *p = new Data;
CalcData( p );
delete p;
}
合理:
char Buf[sizeof(DATA)];
void foo( void )
{
Data *p = new(Buf) Data;
CalcData( p );
}
解析:
new(buf) type;是定位的new语法,它不会真正的分配内存,而是简单的在指定的已分配的内存起点上划分出一段与类型大小匹配的空间,并直接在这段内存上对该类型进行构造对象,并返回对象的指针。由于它没有真正的分配内存空间,因此它的效率是非常高的,在类似于上述例程中,频繁申请和释放一个大对象的操作,定位的new可以带来很大的效率提升。
(连载)