[C++] A safer array size macro

Introduction

Array size macros in C++ are typically ported from C, and so often end up looking something like this.

#define ARRAY_SIZE_UNSAFE(A) (sizeof(A)/sizeof(*(A)))

This will work, however it has no type safety, so you can pass it both an array or a pointer to an array.

This post shows how templates can be used in C++ to create a safer array size macro (this is the same technique that _countof uses in MSVC).

The Code

The test case for our array size macro is shown below. The first usage should compile and produce the correct result (as a compile time constant), the second usage should fail to compile.

const int arr[] = { 0, 1, 2, 3, 4 };
const int *const ptrToArr = arr;

ARRAY_SIZE(arr);
ARRAY_SIZE(ptrToArr);

The implementation of ARRAY_SIZE is as follows.

#define ARRAY_SIZE(A) (sizeof(ArraySizeHelper(A)))

template <typename T, size_t N>
char (&ArraySizeHelper(T (&a)[N]))[N];

I’ll admit that the syntax looks like a confusing mess, so let’s break it down a bit.

  • ArraySizeHelper is a function declaration (it doesn’t need a definition), which takes a reference to any type of array; in my test case above, “T” would be “int”, and “N” would be 5.
  • The return type of ArraySizeHelper is a reference to an array of type “char” the same size as the array passed into the function; in my test case, this produces a return value of “char[5]“.
  • The ARRAY_SIZE macro then takes the size of the return type of the function (which is a compile time constant); “sizeof(char[5])” is 5, which is the correct size for my array.

While this may seem like overkill just to get the size of an array, the bonus is that as ArraySizeHelper only accepts a reference to an array, trying to pass “ptrToArr” produces a compiler error, which is exactly the behaviour we want.

A much more detailed explanation of how this function works is available on the MSDN blog.

 
comments powered by Disqus