Simple STL Map Tricks

STL No Comments »

Let’s say you have two STL std::maps with identical types, and you want to copy all the elements from one to the other. The easiest way to do this is to use map::insert():

typedef std::map<key_type, value_type> map_t;

map_t map1;
map_t map2;

// Copy all elements from map1 to map2
map2.insert(map1.begin(), map1.end());

Alternatively, you could use the STL std::copy algorithm:

// Copy all elements from map1 to map2.
std::copy(map1.begin(), map1.end(), std::inserter(map2, map2.begin()));

Both methods’ performance should be an amortized O(n) because they insert records in sorted order and use the hinting form of map::insert.

Note that because both methods ultimately call map::insert they will not overwrite a preexisting key’s associated value. In other words, if map1 has the value V1 associated with key K and map2 the value V2 associated with the same key K, V2 will remain in map2 after the copy operation.

Let’s say you want to perform the copy but have map1’s values overwrite map2’s for identical keys. The first way to solve this problem that entered my mind was to write my own OutputIterator which performs an overwriting assignment and pass it to std::copy. However, there’s a far simpler approach. You can copy map2’s values into map1, relying on the fact that map2’s values won’t overwrite map1’s, and then swap the results:

map1.insert(map2.begin(), map2.end());
map2.swap(map1);

Thanks, Sam, for helping me figure all this out.

Nesting Dialogs In MFC

MFC No Comments »

Below is a quick tutorial on how to nest a child dialog inside another using MFC (useful when, say, implementing your own tab-strip-like control). Disclaimer: caveat emptor — this method may be flawed, but it works for me.

Read the rest of this entry »

Beware Mixing Libc Versions In Windows

C, C++, Win32 No Comments »

When developing C/C++ applications on Windows, there are multiple versions of the C run-time library to choose from:

  • Single-Threaded (statically linked)
  • Multi-Threaded (statically linked)
  • Multi-Threaded DLL
  • Debug Single-Threaded (statically linked)
  • Debug Multi-Threaded (statically linked)
  • Debug Multi-Threaded DLL

Most of the time you don’t need to concern yourself with this setting. However, different versions of the C run-time library may not play well together.

For example, I recently discovered that if you try to link a piece of code which uses a static version of the C run-time library to a static library which uses a DLL version of the C run-time library, you will get errors of the form:

Linking...
MSVCRTD.lib(MSVCRTD.dll) : error LNK2005: _printf already defined in LIBCD.lib(printf.obj)
LINK : warning LNK4098: defaultlib "MSVCRTD" conflicts with use of other libs; use /NODEFAULTLIB:library
Debug/Exe.exe : fatal error LNK1169: one or more multiply defined symbols found
Error executing link.exe.

Therefore, if you run across errors like this, check that all your projects use the same C run-time library. In Microsoft Visual C++ 6.0, the choice of C run-time library is provided under Project Settings > C/C++ > Code Generation > Use run-time library. Here is a picture of the dialog:

Project Settings Dialog for Visual C++

Avoid Mixing Debug And Release MFC Code Together

MFC No Comments »

If you have an MFC application which uses an MFC extension DLL, be careful not to mix the release version of the EXE with the debug version of the DLL or vice-versa. If you do, many fundamental things will break; e.g. AfxGetApp() will return NULL.

C++, STL, DLLs, and Buggy Optimizations

STL No Comments »

Recently a bug in the STL implementation that comes with Visual C++ 6.0 was brought to my attention. Consider the following function:

typedef std::map<std::string, std::string> map_t;

void f(const map_t& map)
{
    for (map_t::const_iterator iter = map.begin();
         iter != map.end();
         ++iter)
    {
    }
}

For Visual C++ 6.0, if you call f() from within the same EXE or DLL, it works fine, but if calling f() requires you to cross an EXE or DLL barrier, it will fail.

After some debugging, I figured out that this bug is because Visual C++ 6.0’s implementation of std::map, which stores data in a tree structure internally, uses a class static variable to represent a NULL tree node. After putting f() in a separate DLL, the std::map class static value gets initialized to one value in the EXE (on a run on my machine, 0x002f1000) and another value in the DLL (on a run on my machine, 0x003127c0). The ++iter line in the DLL leads to a loop which terminates when it encounters a node it thinks is NULL (0x003127c0). However, as the NULL node was set by the EXE, it has the value 0x002f1000, so the loop within the DLL walks off the tree and crashes.

Per Microsoft Knowledge Base Article 172396: You may experience an access violation when you access an STL object through a pointer or reference in a different DLL or EXE, this is a problem that’s fairly endemic across all of VC++ 6.0 when using STL objects across DLL/EXE barriers. The reason is Microsoft’s STL implementation used class static variables in a number of places to try to avoid storing multiple copies of the same information, but they did not anticipate this DLL-related problem. By the way, this bug is reportedly fixed in Visual C++ 7.

The KB article has a number of suggested workarounds, but I don’t like any of them. Dinkumware, who wrote the Visual C++ 6.0 STL library, has provided a xtree header replacement which fixes the bug by making the value of NULL tree nodes a member of the class rather than a class static variable as part of their Fixes for Library Bugs in VC++ V5.0/V6.0 page, but I don’t like the idea of using third-party compiler header replacements.

My recommendation is to avoid passing STL objects as parameters to DLLs. I also suggest being very careful about using class static variables in your own code.

Data-Driven Programming

C, C++ No Comments »

While this is mentioned in an offhand way in the Assert Yourself chapter of Writing Solid Code by Steve Maguire (an excellent, if dated, read), consider using data-driven programming to simplify unwieldly if and switch blocks. For example, have you ever written code like this?

const char* GetString(int indx)
{
    if (indx == 1) {
        return "foo";
    } else if (indx == 2) {
        return "bar";
    } else if (indx == 3) {
        return "baz";
    } ...
}

The problem with this code is that it is repetitive, makes adding or changing entries difficult, and it can quickly get out of hand. For example, imagine trying to manage over 100 entries in this if block. Now imagine trying to change the indx search method, or the type of indx, or adding many other data points also searchable by indx.

To simplify, we can separate the action from the data by using data-driven programming — put the data into a data structure (I chose a static array, but you could use a binary tree, a hash table, or even an external file) and have the code search this data structure to determine the action to perform. For example:

#define ARRAYSIZE(x) ( sizeof(x) / sizeof(x[0]) )

struct GetStringEntry
{
    int indx;
    const char* str;
};

// These values should be set at compile-time, so no run-time
// costs of setting up the array (which may not be true for other
// data structures).
static GetStringEntry[] g_entries =
{
    { 1, "foo" },
    { 2, "bar" },
    { 3, "baz" },
    ...
};

const char* GetString(int indx)
{
    // Search for the entry with the correct index
    for (GetStringEntry* entry = g_entries;
         entry != g_entries + ARRAYSIZE(g_entries);
         ++entry)
    {
        if (entry->indx == indx)
            return entry->str;
    }

    // Handle error
}

Yes, there’s a lot of boilerplate code (much of which becomes unnecessary with other languages), but it allows great flexibility. Adding a record becomes trivial, and seeing the relationship between an individual indx and str is easy. Want to speed up searching g_entries? Make sure g_entries is sorted and use a binary search algorithm (such as STL’s lower_bound). Want to change indx to a string? Change the type of indx in struct GetStringEntry from an int to a const char*, the indx values in g_entries to strings, and the == comparison in GetString() to strcmp() — far less work than it would be for the original. Want to add another data point searchable by indx? Add a member to struct GetStringEntry, the new values to g_entries, and write another accessor function.

You can use this technique in even more complicated scenarios. For example, imagine a message dispatching system in which each struct contains the message identifier and a pointer to the function that will be executed when the message is received. Imagine searching for an entry by testing to see if the provided value has certain bits set (by using bitwise-and) rather than performing an equality comparison. Future maintenance programmers will thank you as they discover how easy it is to manage, add and modify records, and improve upon code which uses this technique.

C++ Exception Handling

C++, Error Handling No Comments »

Quick quiz: What is the behavior of the following code:

#include <stdio.h>

int main(int argc, char* argv[])
{
    try
    {
        *((char*) 0) = 1;
    }
    catch (...)
    {
        printf("Caught exception.\n");
    }

    return 0;
}

The answer is below the fold.

Read the rest of this entry »

Retrieving Compiler Predefined Macros for gcc

C, C++ No Comments »

To retrieve the list of macros that gcc predefines, execute the following command:

gcc -E -dM - < /dev/null

Implementing IXmlWriter Series

C++, XML No Comments »

While I had originally planned on stretching out my Implementing IXmlWriter series of posts into at least three or four more posts, I’ve decided to end it here. Here is a list of the posts in the series:

Off the top of my head, here are a few things left to implement:

  • Processing instructions
  • Doc type declarations
  • CDATA declarations
  • Entity references
  • Character entities
  • Character encodings (e.g. UTF-8, UTF-16, etc.)
  • Robust error handling, such as throwing an exception if WriteAttribute() is called with an illegal character

Update: 2007-07-11 10:58 PM: Microsoft’s XmlLite provides all this and more for Windows developers.

Implementing IXmlWriter Part 14: Supporting Writing To A Stream

C++, XML No Comments »

Today I will add support for writing the generated XML to a C++ stream to last time’s IXmlWriter.

Read the rest of this entry »

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in