C++ operator overloading trivia

Learned something interesting this week that I'll be working into SafeInt 3. It all started out because if you declare a SafeInt class instance, and then try to use it as an array index, the compiler can't figure out which of the several available integer casts to use for the index. According to the language, an array index should get a ptrdiff_t, which is a 32 or 64-bit signed int, so I'm not sure why the compiler doesn't ask for that, but I digress. I asked an internal alias with a bunch of C++ experts, and immediately got a bunch of questions about why I designed SafeInt to do things the way I did. About the time I was starting to regret asking the question, someone popped up with a question about why I overloaded the Boolean operators (&& and ||), and thought I could replace it with a casting operator to some weird function thing. The initial claim was that this certainly wouldn't cause any side-effects or problems, and given that SafeInt is highly complex, is used thousands of times across Office alone, and it's found more than one compiler bug (not to mention not compiling at all on compilers without really good, current C++ standard template support), I was skeptical to say the least. I was right to be skeptical, as his original suggestion wouldn't even compile at all, but it did lead us to something that's better.

Here's the problem:

#include <stdio.h>

int Bar( int c )

{

    return printf("c = %d\n", c);

}

class PtrThing

{

public:

    PtrThing() : m_pThing(0){}

    bool operator &&( bool b ) const

    {

        return m_pThing && b;

    }

    void* m_pThing;

};

int main(int argc, char* argv[])

{

    PtrThing p;

    if( p && Bar(argc) )

        printf("true\n");

    return 0;

}

Without the overloaded && operator, we can't write a proper if statement using a PtrThing object. We could certainly write another overloaded operator, or a Ptr() method to extract the underlying pointer, and then pass that to an if statement. Given the design goal for SafeInt of being able to replace 'int' with SafeInt<int> and have it not only compile but do the right thing, it seemed reasonable to have an overloaded && and || operator.

However, there's a problem – we're used to things short circuiting. If the first part of a logical AND evaluates to false, we don't evaluate the second, and the converse is true of a logical OR. When you overload the && and || operators, the inputs have to be evaluated, which isn't the way things normally work, leading to programmer astonishment and bugs. This is why it is generally bad to overload these operators, but for SafeInt, it seemed better than not having a logical AND compile at all.

As it turns out, there's a better alternative – overload the cast to bool. Try taking out the operator && above, and add this:

operator bool() const { return !!m_pThing; }

It now not only compiles, but it short-circuits properly. There is a drawback – if I had some situation where a PtrThing could be unexpectedly cast to bool and that wasn't what I wanted, then we could have anything from an ambiguous compile, resulting in errors to an actual runtime bug.

I know this is fairly obscure, and only something that a C++ geek would care about, but I thought it was interesting and could have implications for certain types of classes, especially pointer containers.