mikejsavage.co.uk • About • Archive • RSS • Thanks for blocking ads! Blocking ads owns: AdGuard for Safari / uBlock Origin for everything else
After writing memset( &x, 0, sizeof( x ) );
for the millionth time,
you might start to get lazy and decide it's a good idea to #define
ZERO( p ) memset( p, 0, sizeof( *p ) );
. This turns out to be very easy
to misuse:
int x;
ZERO( &x ); // cool
int y[ 8 ];
ZERO( &y ); // cool
ZERO( y ); // y[ 0 ] = 0, no warnings
int * z = y;
ZERO( z ); // y[ 0 ] = 0
ZERO( &z ); // z = NULL
You can try things like making ZERO
take a pointer instead, but you
still always end up with cases where the compiler won't tell you that
you screwed up. The problem is that there's no way for ZERO
to do the
right thing to a pointer because it can't know how big the object being
pointed at is. The simplest solution is to simply not allow that:
template< typename T > struct IsAPointer { enum { value = false }; };
template< typename T > struct IsAPointer< T * > { enum { value = true }; };
template< typename T >
void zero( T & x ) {
static_assert( !IsAPointer< T >::value );
memset( &x, 0, sizeof( x ) );
}
and as a bonus, we can use the same trick from last time to make it work on fixed-size arrays too:
template< typename T, size_t N >
void zero( T x[ N ] ) {
memset( x, 0, sizeof( T ) * N );
}
Neat! (maybe)