C++

STL Objects and Win32 Module Boundaries
C++ c++ stl win32
Published: 2008-01-04
STL Objects and Win32 Module Boundaries

Let’s say you have the following function:

1
2
3
4
void AppendChar(std::string& s, char ch)
{
    s += ch;
}

What happens if this function is exported as an ordinal function from a DLL (not an inlined piece of code inside a header) and you call it from an EXE?

It works most of the time. When it doesn’t, it corrupts your heap and causes a spectacular mess.

Read more...
Converting C++ Member Functions into Function Objects
C++ c++ stl
Published: 2007-08-28
Converting C++ Member Functions into Function Objects

Let’s say you have a C++ function that takes a function object as a parameter and calls it:

1
2
3
4
5
template <typename _Fn>
void call_functor(_Fn fn)
{
    fn();
}

Now let’s say you want to pass a class’s member function to call_functor() above, as in:

1
2
3
4
5
6
7
class C
{
    void foo() { std::cout << "foo()\n"; }
};

C c;
call_functor(/\* What do I put here? c.foo and &C::foo don't work \*/);

The STL has a pointer-to-member function adapter called std::mem_fun() which almost gets us there. Unfortunately, it doesn’t quite meet our needs because it requires us to pass a pointer to an instance of C, as in:

Read more...
STL Map Use
C++ c++ stl
Published: 2007-01-25
STL Map Use

What’s wrong with the following code?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
template<typename T1, typename T2>
struct my_pair
{
    typedef T1 first_type;
    typedef T2 second_type;

    my_pair() : first(T1()), second(T2()) {}
    my_pair(const T1& v1, const T2& v2) : first(v1), second(v2) {}

    T1 first;
    T2 second;
};

template<typename T1, typename T2>
inline bool operator<
    (
    const my_pair<T1, T2>& x,
    const my_pair<T1, T2>& y
    )
{
    return (x.first < y.first || x.second < y.second);
}

void f()
{
    typedef my_pair<..., ...> key_type;
    typedef ... value_type;
    typedef std::map<key_type, value_type> map_type;

    map_type map;
    // Use map
}

Answer: my_pair cannot be used as a key for a STL map because the operator< violates the rule of strict weak ordering. More specifically, the operator is not antisymmetric. Consider the following:

Read more...
STL Vector Use
C++ c++ stl
Published: 2007-01-23
STL Vector Use

I recently wrote a piece of code that looked something like the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
static const int NUM_TOTAL_VALUES = ...;
typedef ... T;

// Create vec and reserve NUM_TOTAL_VALUES spaces for later insertion
std::vector<T> vec(NUM_TOTAL_VALUES);

// Insert values into vec
for (int i = 0; i != NUM_TOTAL_VALUES; ++i)
    vec.push_back(...);

// vec should now have NUM_TOTAL_VALUES values in it (but doesn't!)

What’s wrong with this code?

Read more...
Managed Wrappers and Hidden Interdependencies
C++ c++ managed c++
Published: 2007-01-10
Managed Wrappers and Hidden Interdependencies

Let’s say you have the following unmanaged code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma unmanaged

class Stream { ... }; // Conceptual stream class

class StreamWriter
{
public:
    StreamWriter(Stream* pStream) : m_pStream(pStream) {}
    ~StreamWriter() { /* Use m_pStream in some way */ }

    ...

private:
    Stream* m_pStream;
};

void f()
{
    Stream stream;
    StreamWriter streamWriter(&stream);

    // Use streamWriter
    // streamWriter is destroyed
    // stream is destroyed
}

Note that StreamWriter’s destructor uses m_pStream (perhaps by flushing the stream). This means that the order of destruction is important — StreamWriter must be destroyed before its underlying Stream is.

Read more...
C++ Exception Handling
C++ c++
Published: 2006-01-30
C++ Exception Handling

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <stdio.h>

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

    return 0;
}

Surprisingly, it depends! As I would expect, on many operating system / compiler combinations (such as gcc version 3.4.4 20050721 (Red Hat 3.4.4-2) as tested by Keith Garner), the dereference of the null pointer leads to a segmentation fault. However, both Microsoft Visual Studio 6.0 and Visual Studio .NET 2003 print the message Caught exception. and exit gracefully. Strange!

Read more...
Be Careful With Doubles And C++ Streams
C++ c++
Published: 2005-09-12
Be Careful With Doubles And C++ Streams

I ran across a piece of code recently that was using ostrstream to convert a double to a string. The code looked something like:

1
2
3
4
5
6
7
std::string DoubleToString(double d) {
    std::ostrstream ostr;
    ostr << d << std::ends;
    std::string str(ostr.str());
    ostr.freeze(false);
    return str;
}

This function was used to convert doubles to strings for insertion into an XML document, which were eventually parsed in an XSLT by the XPath number() function. Most of the time it worked fine, but for really large numbers the number() function failed and return NaN. Why?

Read more...
Use RAII
C++ c++ win32
Published: 2005-09-09
Use RAII

This is covered by any halfway-decent C++ book, but I believe it deserves reiteration: Use the RAII idiom. I don’t think I could explain RAII any better than HackCraft does in The RAII Programming Idiom.

Let me demonstrate how to use RAII with a semi-contrived example. Here’s the pre-RAII code:

1
2
3
4
5
6
7
8
9
HMODULE hm = LoadLibrary(_T("user32.dll"));
if (hm != NULL) {
    FARPROC proc = GetProcAddress(hm, "MessageBoxW");
    if (proc != NULL) {
        typedef int (WINAPI *FnMessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT);FnMessageBoxW fnMessageBoxW = (FnMessageBoxW) proc;
        fnMessageBoxW(NULL, L"Hello World!", L"Hello World", MB_OK);
    }
    FreeLibrary(hm);
}

In this case, the resource wrapped is HMODULE, the resource acquisition function is LoadLibrary(), and the resource release function is FreeLibrary(). Beware of resources which have multiple resource release functions, such as Win32’s HANDLE with FindClose() and CloseHandle(); for these cases you will typically have to write multiple RAII classes. I will call the wrapper class HModule. Here’s how its use will look:

Read more...