Use Constant References For Input-Only Parameters, Pointers Otherwise

This is a style issue, so there is no right or wrong, but I suggest using a const reference for an input-only paramater to a C++ function and a pointer for an input/output or output-only parameter. This makes it slightly more obvious that the parameter might be modified by the function.

Example:

ReturnType Function
    (
    const ParamType& inputParam,
    ParamType* inputOutputParam,
    ParamType* outputParam
    )
{
    // ...
}

void User()
{
    ParamType inputParam;
    ParamType inputOutputParam;
    ParamType outputParam;

    // Note the &s -- this is a bit of a warning something
    // might happen to inputOutputParam or outputParam...
    ReturnType ret = Function
        (
        inputParam,
        &inputOutputParam,
        &outputParam
        );
}

Write Functions Which Take Iterators, Not Collections

If my experience is typical, this is a very common construct:

ReturnType Function
    (
    const std::vector<T>& container
    )
{
    typedef std::vector<T>::const_iterator iterator_t;
    for (iterator_t iter = container.begin();
         iter != container.end();
         ++iter) {
        // Work with *iter
    }
}

The problem with this construct is that you have forced a container choice upon the user of your function. Slightly better, and basically your only choice when interoping with C, is this:

ReturnType Function
    (
    T* array,
    int numItems
    )
{
    for (int i = 0; i < numItems; ++i) {
        // Work with array[numItems]
    }

    // Or perhaps:
    // for (T* pT = array; pT != array + numItems; ++pT) {
    //     Work with *pT
    // }
}

With the above construct you can pass in any container which uses contiguous storage, such as an array or a std::vector (yes, std::vectors are guaranteed to store the data contiguously). Passing a std::vector to the above function looks like:

std::vector<T> v;
ReturnType ret = Function(v.empty() ? 0 : &v[0], v.size());

However, in C++ its far better to do as the STL does and write your function to accept iterators, as in:

template <class InputIterator>
ReturnType Function
    (
    InputIterator first,
    InputIterator last
    )
{
    for (InputIterator iter = first; iter != last; ++iter) {
        // Work with *iter
    }
}

By using this construct, you allow vast usage flexibility. Try to limit yourself to input iterator expressions on first and last (basically preincrement, dereference, and comparison) to minimize the requirements the InputIterator class must fulfill.

Most (all?) STL containers can pass their contents to Function() by using the containers’ begin() and end() functions, as in:

std::vector<T> v;
ReturnType ret = Function(v.begin(), v.end());

As C pointers are random-access iterators, you can pass arrays to Function() as follows:

const int arraySize = ...;
T array[arraySize];

ReturnType ret = Function(array, array + arraySize);

By the way, this lesson also applies to C#: prefer writing functions which accept IEnumerables rather than collections such as arrays. (In C# 2.0, you should be able to regain the lost typesafety by accepting IEnumerable<T>)

Prefer Iteration To Indexing

I’ve seen the following STL construct countless times:

std::vector<T> container;

for (int i = 0; i < container.size(); ++i) {
    // Work with container[i]
}

Unless otherwise necessary, it is better to use an STL iterator because it enables you to more easily change the underlying container. You can isolate the code changes required to one line by using typedef, as in:

typedef std::vector<T> container_t;
container_t container;

// Or ::const_iterator as necessary
for (container_t::iterator iter = container.begin();
     iter != container.end();
     ++iter) {
    // Work with *iter
}

Note that I wrote iter != container.end() as opposed to iter < container.end(). The former only requires an input iterator, while the latter requires a random access iterator—a more complicated iterator type supported by fewer STL containers.

Also note that I wrote ++iter as opposed to iter++. In general, you should prefer the former expression because it is always at least as efficient as the latter, and often times more so.

Of course, for a code block like the one above, you really should consider using the STL algorithm for_each.