Saturday, August 29, 2009

Singleton Gotcha

Hey ho folks,

today I have another small C++ gotcha I wanted to draw your attention to. And I'll demonstrate it with a singleton (In case you don't know what a singleton is, I suggest you google it as quickly as possible and than clear your browser cache so nobody will find out you didn't know).

Let's take a look at the following code:

class MySingleton
{

public:

inline static MySingleton& getInstance()
{
// Create the instance via lazy initialization
static MySingleton instance;

return instance;
}

void foo() const;

protected:
MySingleton(){};
MySingleton( const MySingleton& ){};

};

// mySingleton.cpp
void MySingleton::foo() const
{
std::clog << "MySingleton::foo() was called" << std::endl;
}

Now, this looks just fine, and theoretically we should be able to use it as we are used to:

// Call foo() on our singleton
MySingleton::getInstance().foo();

And you can, and it should work fine. Until you use it from another module and make foo() access a data member of your singleton, that is.

So what's gone wrong here? Well, the culprit is the inline keyword in the declaration of the getInstance() function. Since the function is inlined, some compilers will actually create multiple instances of the static MySingleton instance, thus resulting in different objects being returned for different calls.

So the bottom line is: Be careful with static local variables inside of inline functions. They can lead to bugs that are really hard to track.

Happy coding :)

Thursday, August 13, 2009

Overloading static_cast?

If you have been using C++ long enough, you'll likely have come across situations where you needed your own type conversions. In most cases, this is as simple as adding an overloaded conversion operator to your class, and it will work fine with the regular static_cast.

But what if you are using templates and would like to allow conversion to the same class with a different template type? You can of course provide a templated conversion operator that converts to YourClass< T >.

Here is an alternative solution: Just write your own casting operator. Here is an example:

template< typename T >
struct Vector2d
{
T _x, _y, _z;

Vector2d( T x, T y, T z );
};

template< typename Dst, typename Src >
Vector2d< Dst > geomConvert( const Vector2d< Src >& src )
{
return Vector2d< Dst > (
static_cast< Dst >( src._x ),
static_cast< Dst >( src._y ),
static_cast< Dst >( src._z )
);
}

You can the use the function like this:

Vector2d< float > floatVec = ...;
Vector2d< double > doubleVec = geomConvert< double >( floatVec );

Note that in order for this to work, the destination type must be the first template parameter. If you specify it second, the compiler won't automatically fill in the source parameter for you and you will have to explicitly specify both the source and the destination type in your template arguments.

In most cases, providing a custom overloaded operator is just fine, but in some cases, this solution might come in handy or provide a cleaner interface. It also saves some typing, since you only have to specify the template parameter, not the entire class name including the template parameter.

It is also a way to force explicit conversion, for instance if you are dealing with a lot of data, like and array of 10000 * 200000 floats. Conversion to double then requires calling a specialized function. If you just overloaded the conversion operator, someone not too familiar with your API might carelessly use static_cast or use implicit conversion on your data, even though it causes very expensive data conversion and memory allocation routines to be called.

Hope this is useful, happy coding :)