Monday, 12 October 2009

Lost Souls of memory managment strike forth from the grave

One of the horrible things about memory managers that note down your file and line is the necessity to differentiate them in some way if they're going to be "if safe".

By if-safe, I mean, safe to have mid argument. Any clever memory manager stuff takes line and file to tell you where your allocations were made. The hierarchical one that I wrote for platform was okay, but it's nature lead to needing to invent the "Again" method. That is, I had to because i didn't know about the double indirection of macro token expansion. Of course, I was a fool to think that macros were ever safe, but i didn't realise quite how ghastly they could be.

Would you beleive that the code below:

#define ThingOnLine( X ) Concat( int t ## X, __LINE__ )
#define Concat( X, Y ) Concat2( X, Y )
#define Concat2( X, Y ) X ## Y

compiles fine and does what you think it should, but the code below:

#define ThingOnLine( X ) Concat( int t ## X, __LINE__ )
#define Concat( X, Y ) X ## Y

doesn't.

That's right.

Try it.

There's no substitute for looking at an error log and going WTF.

Simply put, the __LINE__ doesn't get expanded straight away, it takes a couple of indirections until it gets around to it. The reason is probably to do with how dumb the pre-processor is. It could be that it's doing all it can on each pass, and it needs to be double indirect in order to get around to putting numbers on __LINE__ statements on it's first pass before its allowed to join them up in subsequent ones.

Friday, 9 October 2009

CastAssert

I'm going to start adding runtime checks to my casts. Silly?

I'm going to make debug builds check every cast from an int to a char, or signed to an unsigned, actually check to see if any data was lost. I bet that this ten minute fix will save me a couple of hours from now on.

Wednesday, 7 October 2009

Inheritance

You long lost aunt left you loads of cash, but when her solicitor called to give you her rubels, it turned out you'd only overridden the sterling deposit capability.

just found a website called the C++ FAQ LITE, and section 23, part 3 has an interesting take on how to solve the problem of overloaded overrides.

class Person
{
public:
virtual void Deposit( Sterling amount ) { PutUnderBed( ToCash( amount ) ); }
virtual void Deposit( Rubels amount ) { PutUnderBed( ToCash( amount ) ); }
virtual void Deposit( Euros amount ) { PutUnderBed( ToCash( amount ) ); }
}

class Me : public Person
{
public:
// this overrides the deposit mechanism in Person so that it pays straight into my bank account
virtual void Deposit( Sterling amount ) { PutInBank( amount ); }
}

In this code, the Sterling argumented version overrides all of the base class virtuals. When our auntie clips her clogs, she leaves us rubels, but we can't accept because we've not implemented banking our rubels.

Handled Differently:


class Person
{
public:
void Deposit( Sterling amount ) { DepositSterling( amount ) ); }
void Deposit( Rubels amount ) { DepositRubels( amount ) ); }
void Deposit( Euros amount ) { { DepositEuros( amount ) ); }

protected:
virtual void DepositSterling( Sterling amount ) { PutUnderBed( ToCash( amount ) ); }
virtual void DepositRubels( Rubels amount ) { PutUnderBed( ToCash( amount ) ); }
virtual void DepositEuros( Euros amount ) { PutUnderBed( ToCash( amount ) ); }
}

class Me : public Person
{
protected:
// this overrides the deposit mechanism in Person so that it pays straight into my bank account
virtual void DepositSterling( Sterling amount ) { PutInBank( amount ); }
}

Now, stirling goes into my bank account, but rubels still go under the bed, and I can be thankful of having a dead auntie.

This idea of allowing the base class to reinterpret functionality and leave defaults in place is a nice way of securing your code against accidental casts to the wrong type to make things fit where they can go (imagine ignoring the warning that it's converted an int to a float, and much later finding out that it's called the wrong function instead of doing what you thought it should).