Posts Tagged Boost

In Praise of Smart Pointers

hacker_bomb[1]At work I program in C++, which is a great and powerful language but also an inherently unforgiving one that imposes dire penalties for failing to adhere to its ritualized memory-management rules.  Simple programs are easy to make work correctly, but anything complex runs the risk of a memory leak, which can eventually bring a system to its knees, or a double-deletion or dereferencing of a bad pointer, which can cause an instantaneous program crash.

The issue of memory management in C++, in fact, is such a big problem that there are all sorts of methodologies, class libraries, third party tools, and even alternative languages that have been developed, wholly or partially, to avoid this problem.

In my opinion, however, there is nothing easier or more effective in the vast majority of cases than using the Boost library’s (and now the TR1 library’s as well) shared_ptr<> class.  shared_ptr<>, as the name implies, provides shared access to memory, which is compatible with the behavior of raw system pointers — multiple smart pointers can reference, or “own”, the target memory at one time.  This means that you can easily substitute shared_ptr<> objects anywhere you would normally use a raw pointer.

However, unlike raw pointers, shared_ptr<>; objects support internal reference counting, which (except for some obscure circular reference cases) simply makes the memory management issue go away.

An example of how this might (not) work, with old-style pointers:

int main(int argc, char *argv[])
    int *i1 = new int;
        int *i2 = i1; // two raw pointers now point to the same int value.
        delete i1;
        printf("%ld\n", *i2); // if above line is uncommented, we crash due to a deleted object being
        // accessed!  If the above line is commented out, we'll leak the pointer at the
        // conclusion of the program.
    return 0;

With shared_ptr<>, there’s no need to use the manual “delete” operator any more — shared_ptr<> internally tracks how many total shared_ptr<> objects reference the contained object, and deletes it automatically when there are no references remaining.  The code thus simplifies to:

using boost;
int main(int argc, char *argv[])
    shared_ptr i1(new int);
        shared_ptr i2 = i1; // two shared_ptr objects now point to the same int value.
        printf("%ld\n", *i2); // works fine
    } // at the end of this scope, the i2 object gets destroyed, but the reference
      // count in its destructor sees that there is still an outstanding reference, so
      // it's not deleted yet.
    return 0;
} // now i1 is destroyed, the shared_ptr destructor sees that there are no
  // remaining references, and automatically deletes the int.  No crash, no leak,
  // no manual memory management!

Developers like this behavior because they can drop common memory management tasks completely out of their minds and focus on more important implementation issues.  Architects like it because it’s easy to retrofit into large existing codebases.  Managers like it because it’s a magic bullet for stability.

So what’s the catch?  Well, there are a few:

  • First off, it’s a bit slower than using raw pointers.  shared_ptr<> uses an internal reference count, which makes the object larger than a corresponding raw pointer.  This can cause speed issues in certain applications.  However, most higher-level code is not strongly performance-sensitive, so this is usually not an issue.
  • Second, you can’t use the standard casting operators on them.  Boost provides alternative functions to do what you need to do, but their syntax is slightly different, which increases the amount of code you need to change to retrofit them into an existing system, and is one more thing to remember when you’re working with them.
  • And finally, they are verbose.  typedef will definitely become your friend when setting up shared_ptr<> support in a system.  You will likely want to set up a macro for typedef-ing new types of shared_ptr<> objects to cut down on the excessive keystrokes even so.

There’s a lot more to smart pointers in general, and shared_ptr<> in particular than I’ve covered here, but 99% of the time this is all you need to get rolling with them. Obviously, use C# or Java if your application calls for it, but if you are in the C++ world by force or by choice, get with the program.  Folks, it’s almost 2010.  If you’re still using manual memory management in cases where you aren’t certain you need to (and if you’re not certain, you probably don’t need to) you are not being smart. Let smart pointers make your code smart, and give you the time to solve real problems rather than fiddle around with memory.

Tags: , , ,

Type-Safe Message Passing in Win32/MFC — Part 1: The Problem

Statshot-Top-Safety[1]This is the first in what should be a series of  posts about a problem I’m addressing at work.

I work on an application that is fairly old; it’s grown through accretion over the past decade.  There have been a few architectural revolutions during the process of development, but the code is still very much the Visual Studio 6-based C++ MFC application it started as.

One of the areas where we’ve made progress in the past year or so is in the introduction of smart pointers, specifically boost::shared_ptr<>.  When we upgraded to Visual Studio 2005, which has a fully standards-compliant compiler engine, we suddenly gained access to a number of modern C++ libraries, including Boost.  One of the best modules available in Boost is the smart pointer one, and the “best” (most generally useful) smart pointer in that module is boost::shared_ptr<>.

I won’t bore you with the details, but shared_ptr — a “reference-counted smart pointer” — allows you to almost completely rid yourself of the headaches of manual memory management in C++.  It wraps raw pointers in such a way that you can pass them around freely, like any other first-class object in the system, and internal logic in the shared_ptr object will track the number of references for you.  When there are no references left (all copies of the owned pointer have gone out of scope or been otherwise decomissioned) it will automatically delete the wrapped pointer.

The upshot is that this is great behavior, and very useful to us.  We’ve put them in everywhere we could do so easily, and reaped the benefits of stability by doing so.  We’d like to use them in other places, but unfortunately our architecture heavily leverages the standard Windows messaging system.

Invented for Windows 3.1 (or possibly earlier; I’m not familiar with pre-3.1 Windows) way back in the Dark Ages, the Windows messaging system is a way to modularize applications by providing a generic messaging interface.

You make calls by calling PostMessage() or SendMessage() and providing the window handle of your target, the message code you want to send, and a couple of generic parameters that carry information about what you are trying to do.  The calls look like:

LRESULT ret = ::SendMessage(hWnd, WM_MESSAGE, p1, p2);

There is then code on the receiving side that retrieves these messages and dispatches them to the appropriate handler function with the provided parameters. Voila, instant decoupled function call!

This is all great, as far as it goes.  Where the problem comes in is with the parameters.  These (in Win32) are 32-bit integers, and if what you want to send is too large to fit in two 32-bit integers you need to pass the address of the object you want to access as one of the parameters.  Once you’ve done that, you are faced with a number of problems:

  1. How do you ensure the receiver treats the pointer you’ve sent as an object of the correct type?
  2. How do you know whether or not the receiver should delete the object’s pointer after it’s done using it?
  3. How do you even know (in the case of PostMessage) that the object will even be valid by the time the receiver gets around to using it?

All of these are major issues, and unfortunately all of them are easy to get wrong and there’s no way to tell until your code hits a problem and explodes.  There are better message-passing schemes that have been invented more recently (such as signal/slot, etc.) but completely replumbing our application to support these is not an option.  We’re stuck with Windows messaging.

It would be really nice to use smart pointers for these types of calls though, wouldn’t it?  If we could properly use shared_ptr, that would eliminate issues 2 and 3.  And it would be nice to add some compile-time type safety as well to eliminate issue 1.  If you could do this, you’d have a way to pass typed arguments via the Windows messaging system without worrying about memory allocation or ownership issues, and if you made an object typing mistake, the compiler would inform you about it right away, rather than letting your users inform the customer service desk.

This is the problem I’m trying to solve.  More to come!

Update:  I may need to defer writing any more on this until I find out whether my magazine article submissions are accepted or not.  They won’t accept material that’s been previously published, even online.  I’ll keep you informed.

Tags: , ,

The Quern is Stephen Fry proof thanks to caching by WP Super Cache