Bare-metal arrays made safe: a simple protected-pointer template for C++

One of the reasons why C++ is still the professionals’ language is because of its flexibility.  You can use STL collections, and they’ll work as automatically and as safely as anything in Java or C#. Or you can use naked  pointers into unprotected memory, and it will be as fast as old-style C, but just as dangerous.  But, between these two extremes, there’s a need for something as fast and efficient as real memory, but safe – as safe as Pascal.  And that’s a different animal from either.

Why, in this age of collection classes and automatic memory management, would you want to handle bare metal arrays?  I can think of lots of reasons:

  • Because you’re interfacing with something which thinks differently about objects.  It may have a completely different view of strings than string, (it may not have a string class at all, if it’s connected to hardware) but everything knows what a char * is.
  • Because you really care about efficiency.  Something that runs in milliseconds in-situ may slow to a crawl when passed through naive collections, with all their copies and heap-churning.
  • Because, if you’re handling an array of fixed size, you want it to stay that way.  (The STL vector just grows – and scoffs memory – if you exceed its bounds.)  With big problems to solve, unpredictable memory demands (especially in pathological cases) can make or break a program.

The problem with a pointer, of course, is that it could point anywhere.  Consider:

int *p = new int[length];
for (UINT k=0; k<length; ++k) *p++ = 0;

You and I are professionals, right?  We’d never do anything that dumb!  Yeah, right.

But this is so common a problem, in all sorts of contexts, that it has been solved in numerous ways:

  • The memory in your computer: it’s paged.  If the processor ever uses a selector that points to memory that’s been unloaded, the processor is interrupted so it can reload the memory.  Every memory reference is actually checked by the hardware!
  • In Pascal, all arrays are defined using subranges.  It’s not enough to talk about an array like integer[100], you’ve got to define it as  integer[0..99], and then every reference is checked.

All I want, all I’ve ever really wanted, was to be able to check array indexes in C++.  How hard is it to create a range-checked pointer type?  Actually, it’s pretty easy:

ptr<int> p (new int (length)); // whatever a ptr is
for (UINT k=0; k<length; ++k) *p++ = 0;
*p=k; // should exception.

OK, let’s be honest: I do want a little more.  One of the things I’d like is to allocate variable-sized arrays on the stack, rather than the heap.  Stack frames get cleaned up really quickly, and (provided the array’s elements are simple enough that they don’t need their destructors called) it happens automatically:

{   ptr<int> p (static_cast <int *> alloca (sizeof (int)*length), length);
    for (UINT k=0; k<length; ++k) *p++ = 0;
} // should clean up.

And I could seriously do with being able to take subranges from the pointers, which are themselves protected:

int binsearch(ptr<int> p, int q) {
    if (p.size() == 1) return *p;
    size_t midpoint = p.size/2;
    if (q < p[midpoint]) return binsearch (ptr (p, midpoint-1), q); // search the first half
    else return binsearch (ptr (p+midpoint, midpoint), q); // search the second half

I find myself wanting these things so often that I’ve written a protected-pointer template which I find I’m including in pretty much every program I write.  It’s a sort of a safety harness, for use while working at dangerous depths.   Perhaps you’ll find it useful too.  Go get it from here: smartPtr.h.

There’s a few extra things you should know about this.

  • It checks everything when it’s in debug mode (and exceptions if there’s anything it doesn’t like), but in release mode, it just turns into conventional pointers (though see comment about indexing below).  It keeps going if it can.
  • Unlike a pointer, you can iterate using begin() and end().
  • The process of creating an array on the stack is simplified: just use:
ptr<int> p = local_ptr (int, length);
  • There’s an indexed mode as well as a linear mode.  I’m surprised, even in retrospect, how often I find this useful.  But the idea is, if you’ve got an array p, and you want another array q which is like p, but has its elements permuted, you can do that.
ptr<int>p (memory, 8);
ptr<int>q (p,  8, int [] {0,4,2,6,1,5,3,7}); // Not C++ syntax, but you get the idea.  The array is the bit reversals of the ordinals.
q[1]=4;// actually means p[4]=4
// Please note warnings in the comments regarding ownership of the index array!

Guess what – you can keep indexing!

ptr<int>s (q+2, 4, int [] {7,5,3,1});

If you don’t want the indexing (it adds a slight overhead) you can switch it off by #undefining indexable at the top of the file.

So, over to you.  Hope you find it helpful.

That link, once again: smartPtr.h

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s