Programming Challenges:110502 Reverse and Add

I solved the 110502 Reverse and Add problem today. The hardest part was whipping up the worker functions to do text based numbers.

I started by laying out the algorithm in function blocks, then proceeded to full in the gaps. I had two bugs

  1. my is_palindrome function didn’t have a default return value. It was C++ but even that seems a bit broken, but it compiled!
  2. my data structure could hold 10 digits (ie 1,234,567,890) as the problem stated, but that didn’t seem enough. Size 100 fixed that.

I haven’t done any simple problem work for a while, and I like the idea of doing some of the Rudy Quiz (albeit in C#), yet the testing structure of Programming Challenges site makes it a contained experience.

C++ Default Constructors

Well the bug I was getting bitten by at work is shown by the following code.

class c1
{
public:
    int a;
    int b;
};

class c2
{
public:
    int c;
    int d;
    c2(): c(3){};
};

class c3
{
public:
    int e;
    c1 f;
};

class c4
{
public:
    int g;
    c2 h;
};

int main(int argc, char* argv[])
{
    c1 v1;
    c2 v2;
    c3 v3;
    c4 v4;

    c1* pv1 = new c1();
    c2* pv2 = new c2();
    c3* pv3 = new c3();
    c4* pv4 = new c4();

    return 0;
}

With a break point on the return (in debug mode). Inspection shows the 8 variables have the follow values:

v1 {a=0xcccccccc b=0xcccccccc }
v2 {c=0x00000003 d=0xcccccccc }
v3 {e=0xcccccccc f={a=0xcccccccc b=0xcccccccc } }
v4 {g=0xcccccccc h={c=0x00000003 d=0xcccccccc } }
pv1 {a=0x00000000 b=0x00000000 }
pv2 {c=0x00000003 d=0xcdcdcdcd }
pv3 {e=0x00000000 f={a=0x00000000 b=0x00000000 } }
pv4 {g=<strong>0xcdcdcdcd</strong> h={c=0x00000003 d=0xcdcdcdcd } }

now v1-v4 are what I’d expect, pv1-pv3 are also are what I’d expect, but pv4 is not!

Because to break the default c3 members values just takes adding a constructor to c1, then c3 is broken.

Both Visual Studio 2003 and Visual Studio 2005 behave the same. It just seems very strange that the existence of a non-default constructor for one member field means that this object (class or struct) doesn’t get a default constructor.

Now I understand the best solution is to never have a struct or class without a constructor, but it just seems so fragile.

The makes extra work for me to upgrade our legacy code base from C malloc to C++ new, as not been able to rely of the default constructor to zero the ram, means I need to manually set all members to zero for all objects.

*GRRR*

Visual Studio 2005, C++ and Time

Microsoft wisely updated time_t and the ATL CTime and CTimeSpan to use a int64 under the hood (from a int32), this is good except when we have those data types in our interfaces, and now we have broken backwards compatibility.

time_t has a a define you can use force time_t to stay a int32 _USE_32BIT_TIME_T. Unfortunately CTime/CTimeSpan do not respect this. One of our DCOM components packs arrays of objects into a stream. To make the game more fun one object element was a CTime and another was a variable length string. The fun began when another teams Delphi tool unpacked these streams and went off into the weeds because the packed objects were different lengths, thus the variable length string’s length was in a different place. Lots of fun debugging that one.

Anyway, the current solution was to change the object’s to use int32’s instead of CTime/CTimeSpan, and downcast the int64 result from .GetTime() and .GetTimeSpan() to a int32. Now our interface is restored. Ok so we are not future proof, and that app will start to behave fun some time in the future, but this just adds to the code paths that need retiring. Oh the joys of large old systems.