September, 2006

  • The Old New Thing

    You have to free memory with the same allocator that allocated it: Logical consequences

    • 31 Comments

    Everybody should know by now that you have to free memory using the same allocator that you used to allocate the memory. If you allocate with new[] then you have to free with delete[]; if you allocate with LocalAlloc then you have to free with LocalFree.

    Once you've internalized this rule, you can use it to draw other logical conclusions. Consider:

    When I call the PropertySheet function, who is responsible for freeing the memory that was allocated for the phpage field of the PROPSHEETHEADER structure?

    Well, there are two candidates for this responsibility, either the PropertySheet function or the caller of the PropertySheet function. If the PropertySheet function was responsible for freeing the memory, it would have to make sure to use the same allocator that was used to allocate the phpage. But there is no requirement that that memory use any particular allocator. (In fact, a significant portion of the time, the memory is allocated from the stack, in which case there is no explicit deallocation step.) The PropertySheet function would now be required to be psychic and somehow "know" how the memory should be freed (or whether it should be freed at all). Since psychic powers have yet to be perfected in software, this pretty much closes off this line of reasoning.

    The only remaining candidate is the caller of the PropertySheet function. Since that's the code that allocated the memory, it's the one who knows how to free it.

  • The Old New Thing

    In case of fire, go to lunch

    • 22 Comments

    Late one morning, the fire alarm went off at work. Everybody dutifully filed out of the building and waited for the all-clear signal. A few of us looked at each other and said, "Let's go to lunch."

    "I'll drive."

    "Shotgun!"

  • The Old New Thing

    You already know what your target architecture is (or at least you should)

    • 30 Comments

    Sometimes the questions I see make me shake my head in wonderment.

    How do I determine programmatically what processor architecture my program was compiled for? I want the x86 version of my program to behave differently from the ia64 version. Is there some API I can call?

    Note that this person isn't asking whether the program is running on 64-bit Windows. This person wants the program to detect whether it was compiled with an x86 compiler, an ia64 compiler, an amd64 compiler, or whatever.

    But why do you need an API for this? You already know what your target architecture is because you compiled it yourself!

    It so happens that the Microsoft Visual C++ compiler defines several symbols for you automatically (assuming you're not running the compiler in "strict ANSI compliance mode"). If you're willing to tie yourself to the Microsoft Visual C++ compiler, you can use those symbols.

    #ifdef _M_IX86
        // the target architecture is x86
    #else
        // the target architecture is something else
    #endif
    

    If you don't want to tie yourself to a particular compiler, you'll have to pass that information yourself. For example, you could have your x86 makefile pass -DBUILDING_FOR_x86 in the compiler flags, while having the ia64 makefile pass -DBUILDING_FOR_ia64, and so on. This is the approach used by the build utility that comes with the Windows DDK: The DDK's makefile system defines a variety of symbols that programs (and other makefiles) can use to alter their behavior depending on the compilation environment:

    // assumes you use makefile.def
    #if defined(_X86_)
        // the target architecture is x86
    #elif defined(_IA64_)
        // the target architecture is Intel ia64
    #elif defined(_AMD64_)
        // the target architecture is AMD x86-64
    #else
        // some other architecture
    #endif
    

    As we saw in the earlier article, you can also use the _WIN64 symbol to detect that the target platform is 64-bit Windows.

    But the point is that this is all something you control yourself. You're the one who is compiling the program. You know what your target architecture is. No need to ask somebody to tell you something that is already entirely under your own control.

  • The Old New Thing

    Just change that 15 to a 1

    • 51 Comments

    It would be nice and easy to just change that 15 to a 1.

    If only it were that simple.

    In the case described in that article, it's not that a single operation was attempted fifteen times in a loop. Rather, the fifteen operations were scattered all over the program. Suppose, for example, that the network operation was "Get the attributes of this file." The program might be filling in a file listing with several columns, one for the icon, another for the file name, another for the file author, and the last one for the last-modified time.

    for each filename in directory {
     list.Add(new ListElement(filename));
    }
    

    Well, that doesn't access the same file fifteen times. Oh wait, there's more. What happens when it comes time to draw that list element?

    ListElement::DrawIcon()
    {
     if (m_whichIcon == don't know)
     {
      m_whichIcon = GetIcon(m_filename);
     }
     draw the icon for the element
    }
    
    // with this common helper function
    GetIcon(filename)
    {
     if (filename is a directory) {
      return FolderIcon;
     } else {
      return PieceOfPaper;
     }
    }
    

    Okay, getting the icon accesses the file once. You can imagine a similar exercise for getting the file's last-modified time. What else?

    ListElement::GetAuthor()
    {
     if (m_author == don't know) {
      AuthorProvider = LoadAuthorProvider();
      m_author = AuthorProvider->GetFileAuthor(m_filename);
     }
     return m_author;
    }
    
    // where the author provider is implemented in a
    // separate component
    GetFileAuthor(filename)
    {
     if (filename is offline) {
      return "";
     } else {
      ... open the file and get the author ...
     }
    }
    

    Getting the author accesses the file once to see if it is offline, then again to get the actual author (if the file is online).

    So in this simple sketch, we accessed the file a total of five times. It's not like there's a 5 in this program you can change to a 1. Rather, it's a bunch of 1's spread all over the place. (And one of the 1's is in a separate component, the hypothetical Author Provider.)

    It reminds of a story I may have read in John Gall's Systemantics: There was a server product that was having problems under load. Once there were more than thirty simultaneous users, the system slowed to a crawl, but the customer needed to support fifty users. At a meeting convened to discuss this problem, an engineer joked, "Well, we just have to search the source code for the #define that says thirty and change it to fifty."

    All the people at the meeting laughed, except one, who earnestly asked, "Yeah, so why don't we do that?"

  • The Old New Thing

    I think I've just broken the internet

    • 15 Comments

    On our internal blogging discussion mailing list, John Kennedy explained that he was trying to set up a video blog but somehow he ended up including the entire video into his RSS feed. He managed to fix the problem, but apologized:

    If the internet is broken, it was my fault.

    That was funny enough, but Keith Combs chimed in with some technical advice, and then added,

    If you manage to break the internet, it won't be the first time.
  • The Old New Thing

    You're white. Do you want to be in my friend's soap opera?

    • 12 Comments

    What does a Mandarin-speaking American woman in Beijing do? If you're Rachel DeWoskin, you serendipitously wind up the star of a daytime Mandarin-language soap opera called Foreign Babes in Beijing, a show that takes all the Western stereotypes (from the Chinese point of view) and milks them for all their melodramatic worth. (They probably watched too much Dallas.)

  • The Old New Thing

    On the unanswerability of the maximum number of user interface objects a program can create

    • 23 Comments

    The answer to the question "What is the maximum number of window classes a program can register?" is not a number.

    Most user interface objects come from a shared pool of memory known as the "desktop heap". Although one could come up with a theoretical maximum number of window classes that can fit in the desktop heap, that number is not achievable in practice because the desktop heap is shared with all other user interface objects on the desktop. For example, menus and windows go into the desktop heap, as well as more obscure objects like active window enumerations, window positioning handles used by DeferWindowPos, and even how many threads have attached input queues (either implicitly done by having cross-thread parent/owner relationships or explicitly by calling the AttachThreadInput function). The more windows and menus you have, the less space available for other things like registered window classes.

    Typically, when somebody asks this question, the real problem is that they designed a system to the point where desktop heap exhaustion has become an issue, and they need to redesign the program so they aren't so wasteful of desktop heap resources in general. (One customer, for example, was registering thousands of window classes in their program, which is excessive.) In the same way that somebody asking for the maximum number of threads a process can create is an indication that their program is in need of a redesign, a program that registers thousands of window classes needs to be given another look. After all, even just creating a thousand windows is excessive—any UI that shows the user a thousand windows is too confusing to be usable.

    (Pre-emptive link: Q126962: On the desktop heap.)

Page 4 of 4 (37 items) 1234