Recently I’ve found myself stumbling around some C++/CLI code. C++ is a language which I learned years ago and never really worked with seriously, so I’ve been cursing and moaning as I worked. Strange for me to go back to a (partially) unmanaged environment now, with all sorts of assumptions that I have proven to be false. I’ll try to go over some pitfalls and insights I’m having during the visit. This is the first:
The Garbage Collector really spoiled me. I’m not talking about deleting what I instantiated, but all sorts of subtler bugs related to going out of scope. For instance, I had code like this that receives a managed, .NET byte and turns it into an unmanaged char*:
// Pin the managed array to an unmanaged char*.
char* buffer = (char*)pinnedBuffer;
// Now do something with the unmanaged buffer.
Simple enough, but then I found myself needing it in a different method too. My first instinct, of course, is refactor those two lines into a new method to do the array conversion, especially since I had a couple of lines of parameter validation there too. But my new GetUnmanagedBuffer(array
In the managed world, we’re used to one of two scenarios when returning function parameters: either’s a value type that’s copied completely, or a reference type that passes a managed, GCed reference. In both these cases, we know that returning any object from a method is a safe operation.
Additonally, we in managed land are used to refactoring being a safe operation, in most cases. If I don’t have to worry about scope, I don’t worry about extracting any block of code into its own method. In C++, however, I have this constant uncertainty. It will pass with exprience, but I still feel much less safe than I would moving to a different, managed environment.
This was the first installment of Tales from the Unmanaged Side. I’ll see if I have anything else to say the more I work on this