Learn C++

March 6th, 2009
December 11th, 2008

Please report any site issues here

Hey everyone,

I’ve just upgraded the web site to wordpress 2.7. If you’ve noticed that anything has broken, please report it here.

No additional downtime is expected at this time. :)

Thanks,
Alex

December 7th, 2008

5.9 — Random number generation

The ability to generate random numbers can be useful in certain kinds of programs, particularly in games, statistics modeling programs, and scientific simulations that need to model random events. Take games for example — Without random events, monsters would always attack you the same way, you’d always find the same treasure, the dungeon layout would never change, etc… and that would not make for a very good game.

So how do we generate random numbers? In real life, we often generate random results by doing things like flipping a coin, rolling a dice, or shuffling a deck of cards. These events involve so many physical variables (eg. gravity, friction, air resistance, momentum, etc…) that they become almost impossible to predict or control, and produce results that are for all intents and purposes random.

However, computers aren’t designed to take advantage of physical variables — your computer can’t toss a coin, throw a dice, or shuffle real cards. Computers live in a very controlled electrical world where everything is binary (false or true) and there is no in-between. By their very nature, computers are designed to produce results that are as predictable as possible. When you tell the computer to calculate 2 + 2, you ALWAYS want the answer to be 4. Not 3 or 5 on occasion.

Consequently, computers are generally incapable of generating random numbers. Instead, they must simulate randomness, which is most often done using pseudo-random number generators.

A pseudo-random number generator (PRNG) is a program that takes a starting number (called a seed), and performs mathematical operations on it to transform it into some other number that appears to be unrelated to the seed. It then takes that generated number and performs the same mathematical operation on it to transform it into a new number that appears unrelated to the number it was generated from. By continually applying the algorithm to the last generated number, it can generate a series of new numbers that will appear to be random if the algorithm is complex enough.

It’s actually fairly easy to write a PRNG. Here’s a short program that generates 100 pseudo-random numbers:

#include <stdafx.h>
#include <iostream>
using namespace std;

unsigned int PRNG()
{
    // our initial starting seed is 5323
    static unsigned int nSeed = 5323;

    // Take the current seed and generate a new value from it
    // Due to our use of large constants and overflow, it would be
    // very hard for someone to predict what the next number is
    // going to be from the previous one.
    nSeed = (8253729 * nSeed + 2396403);

    // Take the seed and return a value between 0 and 32767
    return nSeed  % 32767;
}

int main()
{
    // Print 100 random numbers
    for (int nCount=0; nCount < 100; ++nCount)
    {
        cout << PRNG() << "\t";

        // If we've printed 5 numbers, start a new column
        if ((nCount+1) % 5 == 0)
            cout << endl;
	}
}

The result of this program is:

20433	22044	9937	30185	29341
14783	29730	8430	3076	28768
18053	16066	26537	100	30493
4943	19511	19251	6669	32117
31575	3373	32383	30496	12710
23999	11929	5425	9938	12107
28541	1938	3450	20283	16726
6440	4938	26094	24391	12248
24803	30416	16244	19590	6644
24646	4873	2841	23831	23476
17958	8827	17400	32129	32760
25744	25405	13591	8859	15932
19086	19666	19265	14179	1165
27168	20996	29427	5857	3434
18964	11980	564	4620	400
17362	16934	11889	419	9714
19808	29699	3694	25612	5512
20256	10009	10247	1860	1846
1487	14030	2615	16035	8107
28736	267	29395	9438	20294

Each number appears to be pretty random with respect to the previous one. As it turns out, our algorithm actually isn’t very good, for reasons we will discuss later. But it does effectively illustrate the principle of PRNG number generation.

Generating random numbers in C++

C (and by extension C++) comes with a built-in pseudo-random number generator. It is implemented as two separate functions that live in the cstdlib header:

srand() sets the initial seed value. srand() should only be called once.

rand() generates the next random number in the sequence (starting from the seed set by srand()).

Here’s a sample program using these functions:

#include <stdafx.h>
#include <iostream>
#include <cstdlib> // for rand() and srand()
using namespace std;

int main()
{
    srand(5323); // set initial seed value to 5323

    // Print 100 random numbers
    for (int nCount=0; nCount < 100; ++nCount)
    {
        cout << rand() << "\t";

        // If we've printed 5 numbers, start a new column
        if ((nCount+1) % 5 == 0)
            cout << endl;
	}
}

Here’s the output of this program:

17421	8558	19487	1344	26934
7796	28102	15201	17869	6911
4981	417	12650	28759	20778
31890	23714	29127	15819	29971
1069	25403	24427	9087	24392
15886	11466	15140	19801	14365
18458	18935	1746	16672	22281
16517	21847	27194	7163	13869
5923	27598	13463	15757	4520
15765	8582	23866	22389	29933
31607	180	17757	23924	31079
30105	23254	32726	11295	18712
29087	2787	4862	6569	6310
21221	28152	12539	5672	23344
28895	31278	21786	7674	15329
10307	16840	1645	15699	8401
22972	20731	24749	32505	29409
17906	11989	17051	32232	592
17312	32714	18411	17112	15510
8830	32592	25957	1269	6793

The range of rand()

rand() generates pseudo-random integers between 0 and RAND_MAX, a constant in cstdlib that is typically set to 32767.

Generally, we do not want random numbers between 0 and RAND_MAX — we want numbers between two other values, which we’ll call nLow and nHigh. For example, if we’re trying to simulate the user rolling a dice, we want random numbers between 1 and 6.

It turns out it’s quite easy to take the result of rand() can convert it into whatever range we want:

// Generate a random number between nLow and nHigh (inclusive)
unsigned int GetRandomNumber(int nLow, int nHigh)
{
    return (rand() % (nHigh - nLow + 1)) + nLow;
}

PRNG sequences

If you run the rand() sample program above multiple times, you will note that it prints the same result every time! This means that while each number in the sequence is seemingly random with regards to the previous ones, the entire sequence is not random at all! And that means our program ends up totally predictable (the same inputs lead to the same outputs every time). There are cases where this can be useful or even desired (eg. you want a scientific simulation to be repeatable, or you’re trying to debug why your random dungeon generator crashes).

But often, this is not what is desired. If you’re writing a game of hi-lo (where the user has 10 tries to guess a number, and the computer tells them whether their guess is too high or to low), you don’t want the program picking the same numbers each time. So let’s take a deeper look at why this is happening, and how we can fix it.

Remember that each number in a PRNG sequence is generated from the previous number, in a deterministic way. Thus, given any starting seed number, PRNGs will always generate the same sequence of numbers from that seed as a result! We are getting the same sequence because our starting seed number is always 5323.

In order to make our entire sequence randomized, we need some way to pick a seed that’s not a fixed number. The first answer that probably comes to mind is that we need a random number! That’s a good thought, but if we need a random number to generate random numbers, then we’re in a catch-22. It turns out, we really don’t need our seed to be a random number — we just need to pick something that changes each time the program is run. Then we can use our PRNG to generate a unique sequence of pseudo-random numbers from that seed.

The commonly accepted method for doing this is to enlist the system clock. Each time the user runs the program, the time will be different. If we use this time value as our seed, then our program will generate a different sequence of numbers each time it is run!

C comes with a function called time() that returns the number of seconds since midnight on Jan 1, 1970. To use it, we merely need to include the ctime header, and then initialize srand() with a call to time(0):

#include <stdafx.h>
#include <iostream>
#include <cstdlib> // for rand() and srand()
#include <ctime> // for time()
using namespace std;

int main()
{

    srand(time(0)); // set initial seed value to system clock
    for (int nCount=0; nCount < 100; ++nCount)
    {
        cout << rand() << "\t";

        if ((nCount+1) % 5 == 0)
            cout << endl;
	}
}

Now our program will generate a different sequence of random numbers every time!

What is a good PRNG?

As I mentioned above, the PRNG we wrote isn’t a very good one. This section will discuss the reasons why. It is optional reading because it’s not strictly related to C or C++, but if you like programming you will probably find it interesting anyway.

In order to be a good PRNG, the PRNG needs to exhibit a number of properties:

First, the PRNG should generate each number with approximately the same probability. This is called distribution uniformity. If some numbers are generated more often than others, the result of the program that uses the PRNG will be biased!

For example, let’s say you’re trying to write a random item generator for a game. You’ll pick a random number between 1 and 10, and if the result is a 10, the monster will drop a powerful item instead of a common one. You would expect a 1 in 10 chance of this happening. But if the underlying PRNG is not uniform, and generates a lot more 10s than it should, your players will end up getting more rare items than you’d intended, possibly trivializing the difficulty of your game.

Generating PRNGs that produce uniform results is difficult, and it’s one of the main reasons the PRNG we wrote at the top of this lesson isn’t a very good PRNG.

Second, the method by which the next number in the sequence shouldn’t be obvious or predictable. For example, consider the following PRNG algorithm: nNum = nNum + 1. This PRNG is perfectly uniform, but it’s not very useful as a sequence of random numbers!

Third, the PRNG should have a good dimensional distribution of numbers. This means it should return low numbers, middle numbers, and high numbers seemingly at random. A PRNG that returned all low numbers, then all high numbers may be uniform and non-predictable, but it’s still going to lead to biased results, particularly if the number of random numbers you actually use is small.

Fourth, all PRNGs are periodic, which means that at some point the sequence of numbers generated will eventually begin to repeat itself. As mentioned before, PRNGs are deterministic, and given an input number, a PRNG will produce the same output number every time. Consider what happens when a PRNG generates a number it has previously generated. From that point forward, it will begin to duplicate the sequence between the first occurrence of that number and the next occurrence of that number over and over. The length of this sequence is known as the period

For example, here are the first 100 numbers generated from a PRNG with poor periodicity:

112	9	130	97	64
31	152	119	86	53
20	141	108	75	42
9	130	97	64	31
152	119	86	53	20
141	108	75	42	9
130	97	64	31	152
119	86	53	20	141
108	75	42	9	130
97	64	31	152	119
86	53	20	141	108
75	42	9	130	97
64	31	152	119	86
53	20	141	108	75
42	9	130	97	64
31	152	119	86	53
20	141	108	75	42
9	130	97	64	31
152	119	86	53	20
141	108	75	42	9

You will note that it generated 9 as the second number, and 9 again as the 16th number. The PRNG gets stuck generating the sequence in-between these two 9’s repeatedly: 9-130-97-64-31-152-119-86-53-20-141-108-75-42-(repeat).

A good PRNG should have a long period for all seed numbers. Designing an algorithm that meets this property can be extremely difficult — most PRNGs will have long periods for some seeds and short periods for others. If the user happens to pick that seed, then the PRNG won’t be doing a good job.

Despite the difficulty in designing algorithms that meet all of these criteria, a lot of research has been done in this area because of it’s importance to scientific computing.

rand() is a mediocre PRNG

The algorithm used to implement rand() can vary from compiler to compiler, leading to results that may not be consistent across compilers. Most implementations of rand() use a method called a Linear Congruential Generator (LCG). If you have a look at the first example in this lesson, you’ll note that it’s actually a LCG, though one with intentionally poorly picked bad constants. LCGs tend to have shortcomings that make them not good choices for certain kinds of problems.

One of the main shortcomings of rand() is that RAND_MAX is usually set to 32767 (essentially 16-bits). This means if you want to generate numbers over a larger range (eg. 32-bit integers), the algorithm is not suitable. Also, rand() isn’t good if you want to generate random floating point numbers (eg. between 0.0 and 1.0), which is often useful when doing statistical modelling. Finally, rand() tends to have a relatively short period compared to other algorithms.

That said, rand() is entirely suitable for learning how to program, and for programs in which a high-quality PRNG is not a necessity. For such applications, I would highly recommend Mersenne Twister, which produces great results and is relatively easy to use.

6.1 — Arrays (Part I)
Index
5.8 — Break and Continue
October 26th, 2008

15.6 — Exception dangers and downsides

As with almost everything that has benefits, there are some potential downsides to exceptions as well. This article is not meant to be comprehensive, but just to point out some of the major issues that should be considered when using exceptions (or deciding whether to use them).

Cleaning up resources

One of the biggest problems that new programmers run into when using exceptions is the issue of cleaning up resources when an exception occurs. Consider the following example:

try
{
    OpenFile(strFilename);
    WriteFile(strFilename, strData);
    CloseFile(strFilename);
}
catch (FileException &cException)
{
    cerr << "Failed to write to file: " << cException.what() << endl;
}

What happens if WriteFile() fails and throws a FileException? At this point, we’ve already opened the file, and now control flow jumps to the FileException handler, which prints an error and exits. Note that the file was never closed! This example should be rewritten as follows:

try
{
    OpenFile(strFilename);
    WriteFile(strFilename, strData);
    CloseFile(strFilename);
}
catch (FileException &cException)
{
    // Make sure file is closed
    CloseFile(strFilename);
    // Then write error
    cerr << "Failed to write to file: " << cException.what() << endl;
}

This kind of error often crops up in another form when dealing with dynamically allocated memory:

try
{
    Person *pJohn = new Person("John", 18, E_MALE);
    ProcessPerson(pJohn);
    delete pJohn;
}
catch (PersonException &cException)
{
    cerr << "Failed to process person: " << cException.what() << endl;
}

If ProcessPerson() throws an exception, control flow jumps to the catch handler. As a result, pJohn is never deallocated! This example is a little more tricky than the previous one — because pJohn is local to the try block, it goes out of scope when the try block exits. That means the exception handler can not access pJohn at all (its been destroyed already), so there’s no way for it to deallocate the memory.

However, there are two relatively easy ways to fix this. First, declare pJohn outside of the try block so it does not go out of scope when the try block exits:

Person *pJohn = NULL;
try
{
    pJohn = new Person("John", 18, E_MALE);
    ProcessPerson(pJohn );
    delete pJohn;
}
catch (PersonException &cException)
{
    delete pJohn;
    cerr << "Failed to process person: " << cException.what() << endl;
}

Because pJohn is declared outside the try block, it is accessible both within the try block and the catch handlers. This means the catch handler can do cleanup properly.

The second way is to use a local variable of a class that knows how to cleanup itself when it goes out of scope. The standard library provides a class called std::auto_ptr that can be used for this purpose. std::auto_ptr is a template class that holds a pointer, and deallocates it when it goes out of scope.

#include <memory> // for std::auto_ptr
try
{
    pJohn = new Person("John", 18, E_MALE);
    auto_ptr<Person> pxJohn(pJohn); // pxJohn now owns pJohn

    ProcessPerson(pJohn);

    // when pxJohn goes out of scope, it will delete pJohn
}
catch (PersonException &cException)
{
    cerr << "Failed to process person: " << cException.what() << endl;
}

Note that std::auto_ptr should not be set to point to arrays. This is because it uses the delete operator to clean up, not the delete[] operator. In fact, there is no array version of std::auto_ptr! It turns out, there isn’t really a need for one. In the standard library, if you want to do dynamically allocated arrays, you’re supposed to use the std::vector class, which will deallocate itself when it goes out of scope.

Exceptions and destructors

Unlike constructors, where throwing exceptions can be a useful way to indicate that object creation succeeded, exceptions should not be thrown in destructors.

The problem occurs when an exception is thrown from a destructor during the stack unwinding process. If that happens, the compiler is put in a situation where it doesn’t know whether to continue the stack unwinding process or handle the new exception. The end result is that your program will be terminated immediately.

Consequently, the best course of action is just to abstain from using exceptions in destructors altogether. Write a message to a log file instead.

Performance concerns

Exceptions do come with a small performance price to pay. They increase the size of your executable, and they will also cause it to run slower due to the additional checking that has to be performed. However, the main performance penalty for exceptions happens when an exception is actually thrown. In this case, the stack must be unwound and an appropriate exception handler found, which is a relatively an expensive operation. Consequently, exception handling should only be used for truly exceptional cases and catastrophic errors.

17.1 — std::string and std::wstring
Index
15.5 — Exceptions, classes, and inheritance
October 26th, 2008

15.5 — Exceptions, classes, and inheritance

Exceptions and member functions

Up to this point in the tutorial, you’ve only seen exceptions used in non-member functions. However, exceptions are equally useful in member functions, and even moreso in overloaded operators. Consider the following overloaded [] operator as part of a simple integer array class:

int IntArray::operator[](const int nIndex)
{
    return m_nData[nIndex];
}

Although this function will work great as long as nIndex is a valid array index, this function is sorely lacking in some good error checking. We could add an assert statement to ensure the index is valid:

int IntArray::operator[](const int nIndex)
{
    assert (nIndex >= 0 && nIndex < GetLength());
    return m_nData[nIndex];
}

Now if the user passes in an invalid index, the program will cause an assertion error. While this is useful to indicate to the user that something went wrong, sometimes the better course of action is to fail silently and let the caller know something went wrong so they can deal with it as appropriate.

Unfortunately, because overloaded operators have specific requirements as to the number and type of parameter(s) they can take and return, there is no flexibility for passing back error codes or boolean values to the caller. However, since exceptions do not change the signature of a function, they can be put to great use here. Here’s an example:

int IntArray::operator[](const int nIndex)
{
    if (nIndex < 0 || nIndex >= GetLength())
        throw nIndex;

    return m_nData[nIndex];
}

Now, if the user passes in an invalid exception, operator[] will throw an int exception.

When constructors fail

Constructors are another area of classes in which exceptions can be very useful. If a constructor fails, simply throw an exception to indicate the object failed to create. The object’s construction is aborted and its destructor is never executed.

Exception classes

One of the major problem with using basic data types (such as int) as exception types is that they are inherently vague. An even bigger problem is disambiguation of what an exception means when there are multiple statements or function calls within a try block.

try
{
    int *nValue = new int(anArray[nIndex1] + anArray[nIndex2]);
}
catch (int nValue)
{
    // What are we catching here?
}

In this example, if we were to catch an int exception, what does that really tell us? Was one of the array indexes out of bounds? Did operator+ cause integer overflow? Did operator new fail because it ran out of memory? Unfortunately, in this case, there’s just no easy way to disambiguate. While we can throw char* exceptions to solve the problem of identifying WHAT went wrong, this still does not provide us the ability to handle exceptions from various sources differently.

One way to solve this problem is to use exception classes. An exception class is just a normal class that is designed specifically to be thrown as an exception. Let’s design a simple exception class to be used with our IntArray class:

class ArrayException
{
private:
    std::string m_strError;

    ArrayException() {}; // not meant to be called
public:
    ArrayException(std::string strError)
        : m_strError(strError)
    {
    }

    std::string GetError() { return m_strError; }
}

Here’s our overloaded operator[] throwing this class:

int IntArray::operator[](const int nIndex)
{
    if (nIndex < 0 || nIndex >= GetLength())
        throw ArrayException("Invalid index");

    return m_nData[nIndex];
}

And a sample usage of this class:

try
{
    int nValue = anArray[5];
}
catch (ArrayException &cException)
{
    cerr << "An array exception occurred (" << cException.GetError() << ")" << endl;
}

Using such a class, we can have the exception return a description of the problem that occurred, which provides context for what went wrong. And since ArrayException is it’s own unique type, we can specifically catch exceptions thrown by the array class and treat them differently from other exceptions if we wish.

Note that exception handlers should catch class exception objects by reference instead of by value. This prevents the compiler from make a copy of the exception, which can be expensive when the exception is a class object. Catching exceptions by pointer should generally be avoided unless you have a specific reason to do so.

std::exception

The C++ standard library comes with an exception class that is used by many of the other standard library classes. The class is almost identical to the ArrayException class above, except the GetError() function is named what():

try
{
    // do some stuff with the standard library here
}
catch (std::exception &cException)
{
    cerr << "Standard exception: " << cException.what() << endl;
}

We’ll talk more about std::exception in a moment.

Exceptions and inheritance

Since it’s possible to throw classes as exceptions, and classes can be derived from other classes, we need to consider what happens when we use inherited classes as exceptions. As it turns out, exception handlers will not only match classes of a specific type, they’ll also match classes derived from that specific type as well! Consider the following example:

class Base
{
public:
    Base() {}
};

class Derived: public Base
{
public:
    Derived() {}
};

int main()
{
    try
    {
        throw Derived();
    }
    catch (Base &cBase)
    {
        cerr << "caught Base";
    }
    catch (Derived &cDerived)
    {
        cerr << "caught Derived";
    }

    return 0;
}

In the above example we throw an exception of type Derived. However, the output of this program is:

caught Base

What happened?

First, as mentioned above, derived classes will be caught by handlers for the base type. Because Derived is derived from Base, Derived is-a Base (they have an is-a relationship). Second, when C++ is attempting to find a handler for a raised exception, it does so sequentially. Consequently, the first thing C++ does is check whether the exception handler for Base matches the Derived exception. Because Derived is-a Base, the answer is yes, and it executes the catch block for type Base! The catch block for Derived is never even tested in this case.

In order to make this example work as expected, we need to flip the order of the catch blocks:

class Base
{
public:
    Base() {}
};

class Derived: public Base
{
public:
    Derived() {}
};

int main()
{
    try
    {
        throw Derived();
    }
    catch (Derived &cDerived)
    {
        cerr << "caught Derived";
    }
    catch (Base &cBase)
    {
        cerr << "caught Base";
    }

    return 0;
}

This way, the Derived handler will get first shot at catching objects of type Derived (before the handler for Base can). Objects of type Base will not match the Derived handler (Derived is-a Base, but Base is not a Derived), and thus will “fall through” to the Base handler.

Rule: Handlers for derived exception classes should be listed before those for base classes.

The ability to use a handler to catch exceptions of derived types using a handler for the base class turns out to be exceedingly useful.

Let’s take a look at this using std::exception. There are many classes derived from std::exception, such as std::bad_alloc, std::bad_cast, std::runtime_error, and others. When the standard library has an error, it can throw a derived exception correlating to the appropriate specific problem it has encountered.

Most of the time, we probably won’t care whether the problem was a bad allocation, a bad cast, or something else. We just care that we got an exception from the standard library. In this case, we just set up an exception handler to catch std::exception, and we’ll end up catching std::exception and all of the derived exceptions together in one place. Easy!

try
{
     // code using standard library goes here
}
// This handler will catch std::exception and all the derived exceptions too
catch (std::exception &cException)
{
    cerr << "Standard exception: " << cException.what() << endl;
}

However, sometimes we’ll want to handle a specific type of exception differently. In this case, we can add a handler for that specific type, and let all the others “fall through” to the base handler. Consider:

try
{
     // code using standard library goes here
}
// This handler will catch std::bad_alloc (and any exceptions derived from it) here
catch (std::bad_alloc &cException)
{
    cerr << "You ran out of memory!" << endl;
}
// This handler will catch std::exception (and any exception derived from it) that fall
// through here
catch (std::exception &cException)
{
    cerr << "Standard exception: " << cException.what() << endl;
}

In this example, exceptions of type std::bad_alloc will be caught by the first handler and handled there. Exceptions of type std::exception and all of the other derived classes will be caught by the second handler.

Such inheritance hierarchies allow us to use specific handlers to target specific derived exception classes, or to use base class handlers to catch the whole hierarchy of exceptions. This allows us a fine degree of control over what kind of exceptions we want to handle while ensuring we don’t have to do too much work to catch “everything else” in a hierarchy.

15.6 — Exception dangers and downsides
Index
15.4 — Uncaught exceptions, catch-all handlers, and exception specifiers