Not too long ago my team had to write up this little tidbit for some internal usage and I thought I’d share it here mainly so that goggle will help me find it later. Maybe you will find it useful as well although I am sure much of this information has already been written about elsewhere.
When we talk about managed code, we often refer to a whole range of services that make up the managed execution environment, services such as: lightweight movable objects, cross-language inheritance and exception handling, 32/64-bit agnostic execution, code access security, type-safe and version-safe linking, automatic lifetime control of objects (GC), array bounds and index checking. However, strictly speaking, it’s possible to target some of these services and not others.
Consider the following definitions:
Managed code: code that provides minimal information for the runtime to find and unwind stack frames.
Managed data: enough information to, in addition to being able to find and unwind stack frames, register any memory structures that contain object references, zero all such references before registration, report any references held in stack locations or registers; enables services such as garbage collection
Type safe code: code that uses only managed data, and no unverifiable data types or unsupported data type conversion/coercion operations (e.g., non-discriminated unions, structure/interface pointers); enables services such as…
Just because code is managed doesn’t mean it uses managed data. Or, if code uses managed data, it is not per se restricted from using unverifiable data types.
On the one hand, in languages that are geared specifically for the CLR, such as C# and VB, managed code and managed data come hand-in-hand.
With C++, developers have a wide range of options. For example, with Managed C++ it’s possible to write hybrid code that runs under the control of the runtime (managed code) but that can do everything that traditional C++ code can do, including unsafe pointer arithmetic. That is, it’s possible to have applications that are managed but do unsafe things traditionally associated with unmanaged code. Of course, it’s a trade off: traditional flexibility versus the benefit of managed services that make memory leaks, references counts, etc. impossible. This trade off generally makes sense in two scenarios. The most common of which is when you are writing in managed code but need to interoperate closely with a large legacy unmanaged code base. The C++ compiler enables you to access any unmanaged code with very high fidelity and little performance penalty. The second scenario for using the fine grained control C++ offers is in the cases where a small part of a managed app needs to drop down to the lowest level for performance reason such as no type checks and no bound checks.
Of course, managed code may not be applicable to every situation. For example when you are making small, targeted changes to a large unmanaged code base the cost of using managed code may not be commensurate with the benefit.