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!
PROJECTNAME error LNK2001: unresolved external symbol "public: static unsigned int const std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::npos" (?npos@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@2IB) PROJECTNAME error LNK1120: 1 unresolved externals
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.
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
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
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 ./bThe 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.
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.