Partager via


When good code goes bad

Reason #26972593-1 why I hate C++ development:  Just fixed up some broken logic pertaining to binding names in the language service.  All tests pass when running debug, but everything fails when running free.  Normally when this happens it's due to me not initializing a variable (what a great feature that is!) and a dummy value was picked that ended up working in debug.  For example you have something like:

if (foo == bar) {

}

And you haven't initilized foo or bar so they both got a dummy value of something like 0xecececec.  So the test works in debug (which follows what you expected because you thought both values would be 0.  However, in retail the values are totally gibberish and it's broken.  Determing what the actual problem is a exercise in unhappiness.  Stepping through retail code is possible, but it's not fun.  My personal favorite is when you have code like:

if (FAILED(hr = DoSomething())) {
    return hr;
}

When you step over the call to DoSomething you'll land on the “return hr;” line making you think that that call failed.  You then step back (or re-run) and walk through the DoSomething method to find out what failed.  It actually didn't fail, but with all the compiler otpimizations in place what you're probably actually seeing is the current location moving to jsut after the return and the IDE just picking an unfortunate location to say where you are.  So you've wasted 5 minutes trying to walk through that code only to find out that there was nothing wrong with it.  Sigh...

Oh well, some day I'll be off this bloody language :-)

Edit: I traced through it and it did indeed turn out to be an unintialized class field.  Why isn't there a warning a can turn on to let me know about this?? Is there a warning that I just don't know about??  I don't think that there are words to express how much I love this language.

Comments

  • Anonymous
    June 20, 2004
    C# might become a better language when Graphics class becomes as good as Win32 API (no, DllImport will not do) and I will not have to call Dispose on every pen/brush/whatever which I don't have to do in C++ (surprise). Unloading asemblies would be another useful addition.
  • Anonymous
    June 20, 2004
    Mikhail: The using statement should call dipose for you and will allow these unmanaged resources to get cleaned up appropriately.

    I believe that unloading assemblies is something that is possible to do (at least in Whidbey).

    You ask for the graphics class to be as good as Win32. But isn't that exactly what DllImport gets you? Direct access to the Win32 api?

    Note: these issues are more with the provided libraries, not with the C# language itself. I think you're asking for more capable libraries that fit better with the .Net model rather than interop libraries to the current unmanaged APIs.

    You may want to look into avalon to see if you like that model better.
  • Anonymous
    June 20, 2004
    Nope, you can't unload assemblies, see http://weblogs.asp.net/jasonz/archive/2004/05/31/145105.aspx. You can reset appdomain if you are lucky to run your code in a separate appdomain.

    I presonally prefer deterministic destruction as one available in MC++, AFAIK.

    As for Win32 API, why would I be writing in managed language then? If you look how ugly managed code looks when it relies on Win32 API call 99% of the time, you'd prefer native :-)

  • Anonymous
    June 20, 2004
    MIkhail: Doesn't dispose given you your deterministic destruction? When you dispose, the resources are freed back to the system.

    Can you give me an example of how ugly it looks? Normally when I've p/invoked i've just passed structs and strings back and forth and it was fine.
  • Anonymous
    June 20, 2004
    The comment has been removed
  • Anonymous
    June 20, 2004
    I find the "using" syntax clumsy when working with multiple resources, and would prefer something like this:

    {
    dispose Brush b;
    dispose Brush c;
    ...
    }

    which would translate into:

    try
    {
    Brush b;
    Brush c;
    ...
    }
    finally
    {
    if (c != null) c.Dispose();
    if (b != null) b.Dispose();
    }
  • Anonymous
    June 20, 2004
    Interesting: I guess I've never minded:

    using (Brush b = ...)
    using (Brush c = ...)
    {

    }

    it's less characters than the dispose keyword :-)
  • Anonymous
    June 20, 2004
    The comment has been removed
  • Anonymous
    June 20, 2004
    Methinks you need to try something like Valgrind ( http://valgrind.kde.org/ )

    Yeah, okay, it's a GPL open source project associated with KDE and it's only currently supported on Linux, but I'm being serious.

    The idea is that it runs an emulation of the X86 processor - much slower than reality, of course - but it [1] tracks each and every single bit (yes - bit level) of memory that a program uses and alerts you to any use of uninitialized values.

    ([1] Well, this is the traditional 'memcheck' skin, at any rate http://developer.kde.org/~sewardj/docs-2.0.0/mc_main.html - other skins can check other things.)
  • Anonymous
    June 20, 2004
    Shannon: I'm aware of the grinned :-)

    However, it has requirements that aren't going to help here, namely glibc.

    I'm not looking for something that will catch the bugs at runtime, I'd rather have a compile time check that would at least warn you
  • Anonymous
    June 20, 2004
    Never thougt about your

    using (Brush b = ...)
    using (Brush c = ...)
    {

    }


    I've always thought I have to write

    using (Brush b = x)
    {
    using (Brush c = y)
    {

    }
    }
  • Anonymous
    June 20, 2004
    Does that alleviate the need for the new syntax you wanted?
  • Anonymous
    June 20, 2004
    If you don't like using unintialized variables just turn on warnings in your C++ compiler.
  • Anonymous
    June 20, 2004
    Which warning tells you that your constructor has not initialized all the variables in the class?
  • Anonymous
    June 20, 2004
    Have a look pc-lint (http://www.gimpel.com/). It checks for uninitialised variables and out of order member assignments to mention just a few.

    Regards
    Lee
  • Anonymous
    June 21, 2004
    You said you didn't intialize a variable, not a class field. There's a warning for variables but not for class fields.
  • Anonymous
    June 21, 2004
    The comment has been removed
  • Anonymous
    June 22, 2004
    the

    using (...)
    using (...)
    {
    }

    construct is very nice... never thought about that :)