Many programmers (in particular aspiring game developers), despite endless advice to the contrary, learn C++. There seems to be a widespread belief that all commercial games are written in C++, along with an idea that it is the ‘only real programming language’ – apparently they missed the earlier, identical memo about C 😉
Now, I am not saying that C++ is a bad language – on the contrary, it is as powerful and flexible as you typically need, and for its intended purpose as a systems language, it does very well. But C++ is a painful language to use, with myriad design flaws, all plastered over by the slow creep of feature bloat. The archaic preproccessor and complicated template mechanism in no way match their counterparts in dynamic languages, and the compilation model is simply heinous.
The language does have a couple of high points – in particular the standard library is excellent, with a wide selection of containers and algorithms, a generally very high implementation quality, and a simple, uniform interface. But to my mind, the most useful (and often undervalued) feature is RAII, “Resource Acquisition Is Initialisation”.
With RAII, we create an object (sometimes known as a ‘handle’) to manage the lifetime of some resource (a file, socket, block of memory, …). The object is designed so that the resource is allocated and/or initialised in the object’s constructor, and destroyed in the object’s destructor.
This means that we no longer have to explicitly manage the lifetime of the resource – just create a handle on the stack, and the resource is automatically created. As soon as the handle falls out of scope, the resource will be destroyed. We can even wrap the handle with a reference-counted smart point (such as boost::smart_ptr), and the resource will now stay alive as long as any client object is using it, and be destroyed as soon as the last client finishes. And the benefits don’t end there either – destructors are called during exception unwinding, which means that our handle will correctly dispose of its resource even in the event of a failure or crash (very important for resources such as global semaphores, which will other wise hang around forever).
So why is this incredibly useful technique not fully present in newer languages, at least a few of which have been billed as ‘C++ killers’? Many of these newer languages offer a limited form of RAII, but at least Java and Objective C lack RAII entirely.
D’s scope keyword, Python’s with statement and C#’s using declaration all provide limited RAII, by allowing resources to have a scoped lifetime, but none of them readily or cleanly support the clever tricks allowed by C++’s combination of smart pointers and RAII, such as returning handles from functions, multiple handles in the same scope, or handles held by multiple clients.
The answer seems to be garbage collection: all of these newer languages are garbage collected, while C++ (at least in its current form) is not. C++ ties RAII to object destruction, which becomes an issue with garbage collection, as most garbage collectors do not guarantee when they will destroy objects, or even if they will destroy objects at all.
But this lack is more than a little annoying to someone who learned to program in C++: take as an example OpenGL vertex buffers or textures. These buffers need to be released as soon as possible (to free up precious video memory), but unfortunately the same vertex buffer may be shared by many copies of a model.
Since we can’t afford to give each model it’s own copy of the buffer, we need to implement reference counting. In C++ this would be as simple as wrapping the buffer object in a smart_ptr, but in any of these languages we have to explicitly implement reference counting in the buffer object, and explicitly call these functions from each client – which isn’t bad for a single type of resource, and a single type of client, but quickly becomes tedious when there are 10, or 20, or even more, and reference counting has to be invoked from 100’s of locations in the code.
Now I finally come to the point behind all this: I have moved away from C++ for the majority of my programming, but I haven’t really come up with a satisfactory solution to this (apart from manual reference counting). So I am fishing for your thoughts and suggestions here – please comment, and let me know how you deal with replacing RAII in modern languages?