Contents

  1. Unresolved external symbol
  2. Locale-based sorting with STL
  3. The point with rethrowing exceptions
  4. Never use time() to initialize srand()
Valid XHTML 1.0 Strict

Notes on C++ programming

Written by Christian Stigen Larsen — this document is in the public domain.

Here I present some notes I've done while programming using C++. They're mostly for my own benefit, collected when information on the subject in question is scarce on the Internet. Hope these notes will help you as well!

Unresolved external symbol

So the linker is giving you a hard time, eh? Most likely you're trying to use conflicting runtime libraries between a library and your host program.

This happened to me when I made a DLL using STL and std::string::npos. The library was compiled using Configuration Properties → C/C++ → Code Generation → Runtime Library: Multi-threaded DLL (/MD). The host program used Multi-threaded (/MT). Change to match, recompile and you should be fine.

I've also experienced this problem while compiling the Crypto C++ library.

Locale-based sorting with STL

If you ever want to sort a vector based on different locales, here's one way of doing it.

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <locale>

using namespace std;

// print contents of vector-of-string
ostream& operator<<(ostream& out, const vector<string>& v)
{
    vector<string>::const_iterator p;

    for ( p=v.begin(); p!=v.end(); ++p )
        out << *p << (p+1!=v.end()? ", " : "");

    return out << endl;
}

int main()
try {
    cout << "Run ``locale -a'' to show all locales."
             << endl << endl;

    vector<string> v;
    v.push_back("Zork");       v.push_back("Anna");
    v.push_back("Habla");      v.push_back("Düsseldorf");
    v.push_back("Dusseldorf"); v.push_back("Cola");
    v.push_back("Ålborg");     v.push_back("Ålesund");
    v.push_back("Übercool");   v.push_back("Ølen");
    v.push_back("Øygård");     v.push_back("Øye");
    v.push_back("Ærbødigst");  v.push_back("Ubåt");

    cout << "Before sorting:" << endl << v << endl;

    sort(v.begin(), v.end(), locale("norwegian"));
    cout << "Norwegian sorting:" << endl << v << endl;

    sort(v.begin(), v.end(), locale::classic());
    cout << "Classical C-style sorting:" << endl << v << endl;

    sort(v.begin(), v.end(), locale("german"));
    cout << "German sorting:" << endl << v << endl;

    return 0;
}
catch(const exception& e) {
    cout << e.what() << endl;
    return 1;
}

Running the program:

Run ``locale -a'' to show all locales.

Before sorting:
Zork, Anna, Habla, Düsseldorf, Dusseldorf, Cola, Ålborg, Ålesund, Übercool,
Ølen, Øygård, Øye, Ærbødigst, Ubåt

Norwegian sorting:
Anna, Cola, Dusseldorf, Düsseldorf, Habla, Ubåt, Übercool, Zork, Ærbødigst,
Ølen, Øye, Øygård, Ålborg, Ålesund

Classical C-style sorting:
Anna, Cola, Dusseldorf, Düsseldorf, Habla, Ubåt, Zork, Ålborg, Ålesund,
Ærbødigst, Ølen, Øye, Øygård, Übercool

German sorting:
Ærbødigst, Ålborg, Ålesund, Anna, Cola, Dusseldorf, Düsseldorf, Habla, Ølen,
Øye, Øygård, Ubåt, Übercool, Zork

The point with rethrowing exceptions

I've been using exceptions for a while, but I recently discovered, much to my embarrassement, that the big deal with exception-handling is actually rethrowing unknown exceptions!

The whole point is that most of the time you don't want to or need to know what to do with an exception. You just want to know something bad happened, clean up after yourself, and let someone else take responsibility. When you rethrow an object from an unknown catch block, a parent catch-block will be able to catch the exact type thrown. See the code for an example:

#include <stdexcept>
#include <iostream>

using namespace std;

void foo()
{
  try {
     throw runtime_error("this is a runtime error");
  }
  catch(...) {
     cerr << "foo(): unknown exception" << endl;
     throw; // rethrow
  }
}

int main()
{
  try {
    foo();
  }
  catch(const exception& e) {
    cerr << "main(): exception: " << e.what() << endl;
  }
}

The program output from above will be:

foo(): unknown exception
main(): exception: this is a runtime error

Never use time() to initialize srand()

Using time() to initialize srand() will set the same seed for all processes launched within the same second. For a lot of real-world appliations, and especially server programming, launching several processes withing the same second is quite common. Use another mechanism instead, such as gettimeofday(), which has microsecond precision.

The C library has been criticized for almost encouraging programming errors (check out D.J.Bernstein's notes on qmail security, especially item 7) but this serious error can't be blamed on the library. I think it's rather the endless examples of using srand(time(NULL)) in many programming books that are to blame.

I've made the mistake myself without thinking, and spent endless hours tracking down bugs related to creating unique temporary files, directories and global identifiers — only to discover the mistake was relying on srand(time(NULL)). Doh!

Here is an example:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>

int main()
{
  long n = time(0);
  srand(n);
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
}
Try running the program within the same second (a situation that was quite likely to happen in my particular project):
$ g++ b.cpp -ob
$ ./b & ./b
[2] 2540
process 2541 with srand(1114696702) gives rand() = 41723696
process 2541 with srand(1114696702) gives rand() = 1589526122
process 2541 with srand(1114696702) gives rand() = 1777890300
process 2541 with srand(1114696702) gives rand() = 1734233550
process 2541 with srand(1114696702) gives rand() = 1448537050
$ process 2540 with srand(1114696702) gives rand() = 41723696
process 2540 with srand(1114696702) gives rand() = 1589526122
process 2540 with srand(1114696702) gives rand() = 1777890300
process 2540 with srand(1114696702) gives rand() = 1734233550
process 2540 with srand(1114696702) gives rand() = 1448537050
[2]-  Done                    ./b
The two processes produce the exact same number-sequences! And thus my servers could not run parallell jobs anymore. The situation is easy to correct by using microsecond precision instead:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>

int main()
{
  struct timeval tv; // C requires "struct timval" instead of just "timeval"
  gettimeofday(&tv, 0);

  // use BOTH microsecond precision AND pid as seed
  long int n = tv.tv_usec * getpid(); 
  srand(n);

  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
  printf("process %d with srand(%d) gives rand() = %d\n", getpid(), n, rand());
}
Running the new modified program produces different pseudo-random number sequences:
$ g++ e.cpp -oe
$ ./e & ./e
[2] 3225
process 3225 with srand(1460570250) gives rand() = 1910649397
process 3225 with srand(1460570250) gives rand() = 1906913995
process 3225 with srand(1460570250) gives rand() = 807118710
process 3225 with srand(1460570250) gives rand() = 713843545
process 3225 with srand(1460570250) gives rand() = 1459102608
process 3226 with srand(1478640326) gives rand() = 1097638399
process 3226 with srand(1478640326) gives rand() = 1244833615
process 3226 with srand(1478640326) gives rand() = 909145436
process 3226 with srand(1478640326) gives rand() = 629164417
process 3226 with srand(1478640326) gives rand() = 1291362289
[2]-  Done                    ./e

Variations: I've seen in e.g. the Nmap source that one XORs some values to seed the pseudo-random number generator:

srand((tv.tv_sec ^ tv.tv_usec) ^ getpid());

Just thought I'd put it in here, as it's an even nicer way to seed the PRNG.

Not only are rand() and srand() old-fashioned and give pseudo-random numbers of low quality low quality — they're also incredibly slow! Don't believe me? Try doing some serious realtime graphics programming using rand() and check out the framerate. You can measure it by counting out loud, that's how slow it is.

Most people that do (or try, like me) to do serious programming nowadays will not use rand(). Either read up Knuth's books, or if you're in a hurry, get yourself a proper library. Some systems provide hardware-support for generating numbers as well. Check out the Crypto++ source-code for good examples on getting pseudo-random numbers. Many people use the Mersenne twister for speed and quality.

Update

The C++0x standard proposal includes a couple of new pseudo-random number generators. I am happy that they have finally included the Mersenne twister, which is the PRNG most people use nowadays for non-cryptographic applications.