Reflection on unmanaged coding guidelines


Recently I got asked to review a set of internal coding guidelines – unfortunately they were for unmanaged code…  I admit it has been a while sense I  have written much unmanaged code and I was amazed at how many guidelines are just taken care of in managed code.  The nature of the CLR and languages just take care of the issue out of the gate.    


 


Here are a few examples:


 


Always initialize variables when you declare them


You should also always initialize output parameters in a standard way.  For example:


Initialize pointers to NULL


Initialize numerics to zero


In managed code, the CLR initializes references to null and numerics to zero even for value types.  So this guideline is no longer needed.


 


 


Never do anything that can fail in a constructor- use an init method instead


In managed code it is perfectly fine to throw an exception from your constructor.  The GC will guarantee the memory is freed and finializer is run if needed.


 


Use safe string API’s to avoid overwriting buffers


Many times some sporadic memory access violation bug will show up when the program is running. One of the sources of this that some string buffer might have been overwritten unexpectedly.


This is one of my favorites – With the typesafty of managed code and the modern design of the BCL this problem is all but eliminated.  All the System.String APIs are safe!


 


Minimize the use of multiple implementation inheritance


This is a case of addition through subtraction principle.  The platform is net better without this feature


 


What is your favorite unmanaged (C\C++, etc) guideline that just goes away in managed code?

Comments (7)

  1. Johan Ericsson says:

    Those aren’t really that great guidelines for unmanaged C++ development either:

    * Always initialize variables when you declare them:

    – use smart types that initialize themselves

    * Never do anything that can fail in a constructor

    – that’s nonsense… exceptions were not introduced in .NET. Exceptions can be effectively and safely used in C++ (See Boost)

    * Minimize the use of multiple implementation inheritance

    – I’m not sure I understand everyone’s concern with this one. I’ve never seen a problem with multiple inheritance, so I can’t believe that it’s a really common problem. A good counter-example is ATL. With the wide-spread use of ATL, this guideline seems even more dated.

    Of course, the string guideline is one that does ring true and .NET does solve this problem.

    Anyways, I just wish people stopped looking at .NET solving all sorts of problems that were already solved in C++. Don’t get me wrong, I love .NET, but it is not a silver bullet.

  2. bar says:

    Johan mentions the nonsense regarding exceptions, but what’s missing here is use RIIA (resource-initialization-is-acquisition).

    This is one of the things that makes exceptions safe; all your resources are freed when your destructors run as the stack unwinds.

    Of course, the CLR doesn’t exactly offer this (other than try/finally, which C++ doesn’t offer), so I can see how you’d forget about this after spending so much time in the managed world :).

    You could also take this a step further – use <algorithm>. Particularly things like for_each.

  3. Pavel Lebedinsky says:

    >* Always initialize variables when you declare them

    >

    >> use smart types that initialize themselves

    Most people don’t use smart types for things like int and bool so the guideline is still needed. (And many existing smart types like CComXxx stuff in ATL require their own set of guidelines to be used safely).

    My favorite unmanaged guideline that goes away in managed code:

    Don’t do anything non-trivial in DllMain or global C++ constructors.

  4. David Levine says:

    >> managed code it is perfectly fine to throw an exception from your constructor. The GC will guarantee the memory is freed and finalizer is run if needed.

    I disagree with this statement – I believe you are much better off using an init method just as you recommend for unmanaged code. There are two main reasons.

    First, if you throw an exception in a static constructor then the type becomes unusable in the appdomain – further attempts to create an instance of that type will fail with a TypeLoadException.

    Second, I’ve seen too many cases where naive programmers used too much code into a constructor, especially potentially slow or failure-prone code, including web service calls, disk IO, etc. If the CTOR is for a form then the actual display/loading of the form becomes painfully slow.

    I’d prefer to see the rule be that all that should be done in a CTOR is to set the member fields to a value such that the finalizer/Dispose method always has the context necessary to correctly cleanup the object.

  5. Brad Abrams says:

    David — I am not crazy about init methods becuause I think they create an ugly, errorprone programming model. But I do agree that you have to be careful with what you do in the static constructor… (We should add your suggest to the design guidelines and FxCop). As for your secound suggestion, I agree as well and in fact it is already covered in the Design Guidelines:

    Minimize the amount of work done in the constructor.

    <qoute>

    Constructors should not do more than capture the constructor parameter or parameters. This delays the cost of performing further operations until the user uses a specific feature of the instance.

    </qoute>

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconconstructorusageguidelines.asp

  6. Jerry says:

    I would like to comment on typesafety of managed code – it only offers runtime typesafety, not compile time. It will change once generics are implemeneted but meanwhile we have to explicitly catch System.InvalidCastException in cases where C++ templates would throw compile time errors. Personally this bugs me a lot more than remembering to use safe string APIs…

    Oh and what’s the hidden cost of foreach (except an enumerator being instantiated)?

  7. hgkf says:

    gjgdjggngmkhhhk