I’m hardly a behemoth of jollity back in the world of C++ at the moment. Much as a think it is an excellent language, I am reminded that is so open to abuse. Take the following example I recently stumbled across.

try
{
  ...
  ...

  throw "Floating point error"
  ...
  ...
}
catch(const char *e)
{
  string strError(e);
  if (strError == "floating point error")
  {
    ...
    ...
  }
  else if (strError == "some other error")
  {
    ...
    ...
  }
  else if (strError == "some violation")
  {
    ...
    ...
  }
  else throw;
}

Clearly this is open to all sorts of problems. Probably the most obvious it breaks when the string content changes due to capitalization and the floating point error never being seen. However, for me the most significant problem here is a fundamental misunderstanding of what exceptions are really all about.

The author of this code is trying to catch an exception based on its value and not its type. A string literal contains practically no information about the type of exception being thrown. It’s no different to using a string to represent a float or complex number. You can do it but you’d be making hard work for yourself.

And this isn’t confined to string literals. Throwing ints, floats or any predefined type has all the same issues. Once caught, there is no real type information, so you can’t be sure what it represents and have to jump through hoops to fathom how to deal with it –  the Temple of Doom!

I’m not going into a long technical treatise about C++ exceptions; there’s plenty of books and online material that cover it much better than I could. However here’s some bullet point reminders I tend to keep in my head for such occasions that are mostly obvious.

  • exception types are abstract data types representing an exceptions.
  • provide some standard method (what) that describes the exception and maybe a code.
  • better still, derive from a standard exception type. You can then catch the specific type or the base class type.
  • make sure you’ve got a non-throwing copy constructor and destructor in place.
  • don’t throw exception pointers. The address of the exception pointer will be somewhere on the heap and isn’t protected for the duration of the catch. A temporary stack based exception is guaranteed to be safely persisted until the exception has been handled, regardless of platform and compiler.
  • throw by value and catch by reference
    • you prevent unnecessary copying of large exception objects
    • you ensure that modifications applied to the exception within a catch clause are preserved in the exception object if it is re-thrown
    • you avoid slicing of derived exception objects
    • you’ve got less work to do!

As Short Round said – “I keep telling you, you listen to me more, you live longer!”

Advertisements

Last month I had to spend some time porting a Quant pricing library from Linux to Win32. I don’t think it was ever envisaged this code C++ would be cross platform, so it turned out to be more gruelling than I first imagined. Having put in the usual sprinkling of #ifdef Win32’s, sorting out the threading library issues (pthreads fortunately), getting it compiled, linked and tested I reflected on how great some of the features are in Visual Studio 2005 – things I just take for granted.

Understanding and reading pre-processor directives can be a real pain and give you very confusing compiler errors. VC2005 has the very helpful feature of greying out #ifdef code provided the directives are defined in the project. And yes I just take for granted.

A good job done and back to the world of C# – or so I thought.

It seems our client wants some thread safety improvements to this code and driver that uses it. And it all needs to compile cross platform (Win32 and Linux), so the big question is what development environment to use for Linux? Obviously I’m using VC2005 for the Win32 version, but vi for editing on a Linux box – not a chance.

I’ve previously used MinGW and Cygwin, but they aren’t great environments and as it turns out, the project already has a solid command line build working using makefiles so it makes sense not to duplicate all this. I forgot to say the complete project has many sub-projects and comprises many thousands of source files!

So I turned to Eclipse CDT and the plan was to run it on my XP machine with all the src files mapped using Samba on the Linux box. I also wanted to remote compile and debug to make my life easy and have good CVS integration. Although Eclipse CDT should be able to manage this true cross platform development I was wary of what the latest CDT was like. I‘d used an early version and it was quite frankly, rubbish.

So what’s all this ramble leading up to? Well it’s all possible and works pretty well, but there are a few gotchas. So here’s Dave’s guide to setting up CDT for cross (remote) platform development.

  • Put your src on a samba mount on the Linux box and map it to a drive on your dev PC.
  • You’ll need the Eclipse SDK and the CDT (C++) plugin from www.eclipse.org
  • You’ll also need plink.exe that comes with putty, as well as your generated public key file .ppk to seamlessly ssh onto the linux machine with plink. Use linux ssh-keygen to generate the ppk file. Be warned, the latest version of plink (0.59) does not work properly with Eclipse, use version 0.58 or will get the reather unfriendly message ‘Unable to read from standard input’ in the Eclipse console window when you are compiling. (It took be ages to fathom this).
  • Create your workspace and add a new standard makefile project.
  • Uncheck the default location and point it to your Samba mount with the src files.
  • Finish the new project wizard and let the indexer finish it’s stuff.
  • Now the magic – getting the make to compile and link remotely, assuming there is a makefile in the target Linux directory. In the project properties, deselect the Make builder ‘Use default’ and set the build command to be something like this:
    • c:\plink.exe -i c:\key.ppk dave@linuxbox cd `echo '${project_loc}'|sed -e 's^\\\\^\/^g'|cut -c4-`; make
    • where
      • key.ppk is the generated public key file
      • dave@linuxbox is your account on the Linux box
      • ${project_loc} is the Eclipe macro for the local project location, say x:\dev\myproject
      • the rest is a script to replace Win32 slashes to Linux slashes and remove the mapped drive letter, so x:\dev\myproject becomes /dev/myproject

You should now be able to select build project and watch the output in the Console window.

Obviously this is only a guide and you’ll need to change the specifics.

And the conclusion. Version 3.1.2 is much better than the last version I used. Once you get the include paths set up correctly, the content assist works very well and now I’ve changed to keyboard shortcuts to be like VC2005 I’m almost happy.

However I was disappointed pre-processor directives didn’t grey out code and I felt I was back to where I started. This is essential for cross platform development, because it’s so easy to make a mistake when you have a plethora on nested #ifdefs

So I downloaded the latest beta of CDT 4 (M5) and it’ pretty impressive. The highlights for me up to now are:

  • It understands pre-processor directives and greys out code appropriately
  • The call and type hierarchy windows
  • The errors and warnings in the output window link directly to the code window and are shown underlined with tool tips showing the error or warning text.
  • The outliner makes navigating a complex dependency graph understandable
  • The CVS integration is excellent. PushOK works reasonably well in VC2005, but it’s not a patch on the CVS perspective

Remember you’ll need the Eclipse SDK v3.3 to run the CDT v4

So am a happy or cross platform developer? Once I get the gdb debugger integrated, I’ll be reasonably happy. Then again, I’m told I’m difficult to please!