I know I've said this before, but VirtualBox kicks ass. It has that whole "it just WORKS" feel to it. I realise that repeating yourself is supposedly one of the hallmarks of a bad blog, but please indulge me this once; VirtualBox deserves your attention. The image to your right shows virtualbox running windows XP - I'm installing Qt4.4 in the hope that some of the bugs I mentioned in my previous post have been cleaned up.
I'm also compiling the latest KDE4, which is where a multi-core system would be really nice. Until then, I'll continue to struggle with my old box.
I posted previously that I just didn't "get" twitter. I guess this sums up my objections pretty well; unless you have anything interesting to say, stay silent. Do we really need one more idiot blathering on about the most mundane details of his life? I think not.
However, it turns out that the cost of my stubbornness to jump on the twit bandwagon has grown to the point where I am now on twitter. That's right, I'm bowing to peer pressure, and have officially jumped on the twit wagon - You can see my last twitter updates on the right, or you can follow me on twitter.
Now the entire world can join me in my mindless ramblings... of course, if you're reading this then you've already had that pleasure!
Waaaaay back in Janurary I mentioned that I might build my own wireless router. Well, like most of my projects I got half way then got distracted. The other day i got fed up with the lack of wireless (I needed to get my Wii online, apart from anything else), so I splashed out and bought a Buffalo Air-Station (£45).
This baby comes pre-loaded with the open source dd-wrt firmware. It was dead-easy to set up, and boy, what a difference the open firmware makes! This is easily the best router firmware I have ever seen - it boasts more feature than you can shake a stick at. Better yet - it's aimed at people who know what they're doing, and doesn't try to hide it's functionality behind restrictive setup "wizards".
All in all, I'm a very happy man with my new wireless network ;)
One of my pet peeves with regards to C++ is how very few people understand how the delete operator handles NULL pointers. Let's see if you pass the test!
Question: What happens when you do this:
myType *ptr = NULL;
Well? Your choices are:
a) Crash, bang, boom, your computer is now a very heavy paperweight.
b) Nothing - the delete line ignores the ptr to be deleted.
It turns out that deleting a null pointer is safe. Section 5.3.5/2 of the C++ standard states that:
"In either alternative, if the value of the operand of delete is the
null pointer the operation has no effect."
This has been a pet peeve of mine for a while now. I can't count the number of times I've seen programmers write something like this in class destructors or cleanup methods:
This is stupid for several reasons. For a start, the if statement is redundant - if the pointer is NULL the delete will do nothing. Secondly, the programmer never sets the pointer to NULL after deleting it, which means that if this code were to be called again, you would definitely experience problems.
In order to avoid these issues, and avoid angering me if I ever see your code, you should:
- Always initialize pointers to NULL if you're not going to set them to something else straight away (i.e.- if the pointer is not always used).
- Always set them to NULL after you delete them, especially if there's a chance that the delete can be called twice.
There is a kipi plugin that is supposed to be able to do this, but it has not yet hit the Linux distribution I am using, and I'm not about to start compiling plugins from source. Besides, half the fun is in making the application!
This is definitely not a finished application! I got it to the point where I could upload my images in a batch, but it needs more work before it's useful to anyone else. Here's a few sample screen shots:
The application still has a long way to go. Just some of the things yet to complete are:
- Remove hard coded items from the code (account details, service host, album name), and make these configurable via a nice configuration dialog. Make sure password is stored in a secure form - via the KDE wallet perhaps.
- Make the GUI half-decent. Originally I just wanted something to work - I need to go back and do it again with a proper menu and image thumbnail support.
- Bug fixes too numerous to mention here... this is some rouch, cheap and nasty code!
Perhaps, once I get all this done I will attempt to get it officially released into some distros. I think it's a useful application, and the kipi plugin version doesn't seem to be moving along much. Yes, I realize that I'd be better off spending my time improving the kipi plugin, but to be honest I can't be bothered right now - this was a learning experiment for me as much as it was about making an application that solved one of my problems.
The entire application is written in C++ and Qt4. The more I use Qt the more I like it. This application was simplicity itself to make, and I look forward to continued development.
That's "pimpl", not "pimple" - I'm talking about opaque pointers, these beauties help protect your public interfaces from changing implementation. This useful technique has a few drawbacks that aren't so well publicised. In order to prevent others making the same mistakes I have, I thought I'd outline the general use of the pimpl pointer, and some of it's drawbacks:
Here's an example of a first-pass class to encapsulate a user account (I'm making this up on the fly, so bear with me):
// public methods go here
// private data members:
unsigned int accountId;
This will work just fine, but there's a problem. If you need to change the implementation (say you want to store the user's real name in two fields instead of one), unless you're very careful you will end up changing the size and / or the declaration of the class.
Changing the size of the class is a big problem if you're trying to maintain binary compatibility. Changing the declaration of the class is a problem because (some) compilers will now recompile every file that includes your changed header file, even if the changes make no difference to the binary output.
The solution comes in the form of an opaque pointer, or "pointer to implementation" (which is where we get the charming "pimpl" name from). The idea is that the implementation details are put in a separate class that is forward declared in the header file, and fully declared in the cpp file. Your external interface now only contains a single pointer - you can change the size of your implementation class to your hearts content, and you will never change the size or declaration of your external interface. The class above refactored to use a pimpl pointer looks like this:
// forward declare implementation class:
// public methods go here
// private data members:
unsigned int accountId;
: pimpl(new userAccountImpl)
Now any data members can be accesed via the private implementation class. There are several things you can do to extend the example above (using a shard_ptr is a start), but I want to keep things simple for the sake of the example.
Until recently, I took this method for granted and used it as often as I could. As so often happens when I learn something new I rush to use it in every possible situation, including ones where it doesn't make sense. The pimpl idiom has a few problems associated with it, which I will outline here:
- Your object's memory footprint is now split into more than one place in memory. This may not be a huge problem for 90% of classes, but consider a small utility class that contains only standard data types:
// public methods go here
unsigned char red;
unsigned char green;
unsigned char blue;
In order to serialise this into a buffer (like a file), you can get away with using a memcpy or similar technique. Since your object's memory footprint is contiguos, copying the entire object into a file is simple (Yes yes, I know: there are many reasons why this isn't a good idea, but let's face it - this happens all the time). Once you start using pimpl pointers it gets a bit more difficult. Since your implementation class is private to the .cpp file, the code to do the copying needs to be in the same cpp file (otherwise it doesn't have access to the definition of the implementation class). This is relatively easy to work around, but the trouble doesn't stop there - consider what you need to do to un-serialise an object from a buffer. You can no longer be cheeky and use a reinterpret-cast like so:
colour *pCol = (colour*) pBuffer;Again - I realise that this isn't the best idea in the world, but when you're programming with constraints sometimes this is the best way to do things.
- The default new and delete operators are expensive. I never realized just how expensive they can be. In a recent bout of performance testing on some real-time software I saw the default new operator take 55ms to allocate a block of 4B of memory. That's way too slow for the real-time application i was working on, and may be too slow for other applications as well. What's more, the times get worse the more memory you allocate - so using the pimpl pointer may not be a good idea at all, since it adds the overhead of a new call to each constructor, and a delete to each destructor. ouch!
If you're looking for more info on the pimpl idiom, Sutter wrote a good article on the pimpl pointer, and a more recent article that talks about some of the performance issues associated with pimpl pointers. This technique is worth using - it can save many attacks of "code cheese" in the future, just be careful where you us it, or you may end up with some nasty performance issues you didn't expect!