Tag Archive for 'C++'

Can references be null?

I often hear people insist that C++ references can be null.

You can easily create a null reference like this:

int *ptr = 0;
int &ref = *ptr;
// ref is a null reference

First, there is no such thing as a null reference in standard C++.

Like all programming languages, C++ is purely a construction of the human mind, and the concepts of the language have been given arbitrary but meaningful names as part of the standardization process so that the users of the language could understand each other. These could be existing words such as class, aligned, statement, pointer or new ones like rvalue or cv-qualified.

In particular, the C++ standard does define a null pointer, but it does not define a null reference because that concept is not part of the language.

This means that instead of having a standard definition (like a null pointer), null references have a commonly accepted definition that follows a similar schema: a null reference is a reference r such that &r is a null pointer. For the rest of this article, I will follow this definition.

Second, a null reference cannot exist in a well-behaved program.

Since the concept does not appear in the standard, it’s pretty obvious that no place in the standard explicitly mentions an operation resulting in a null reference being constructed. In fact, the description of how references are constructed explains that references are constructed from other values, and by definition values cannot have a null pointer for an address.

In particular, the typical construction of a null reference by dereferencing a null pointer is explicitly mentioned in the standard, and described as undefined behavior.

In short, while many modern implementations will let you create a null reference, this will necessarily involve some form of undefined behavior along the way.

I tend to evaluate programmers on a “would I hire this person?” basis. So, what does the “C++ references can be null” statement tell me about someone ?

  • They might be confusing C++ references with C# or Java references, which can be null. Certainly a NO HIRE for a senior C++ programmer.
  • They might have misread their textbook and genuinely think references can be null in the same way as pointers (except, well, the lack of syntactic sugar for checking if a reference is null or creating a null reference strikes me as odd if that were the case). Again, NO HIRE for a senior C++ programmer.
  • They know it’s not standard, but they do not care about writing standard programs. This is an immediate NO HIRE even for junior C++ programmer.

Then, there are those who know about it, and would not use it because they care about writing standard programs. The convention when discussing C++ is to assume that the program is well-behaved, so most people would parse “C++ references can be null” as “C++ references can be null in a well-behaved program”, the latter being obviously incorrect. I don’t really mind a small misunderstanding, the subject being as complex as it is, as long as it’s corrected quickly.

A person who does not is either someone without much experience discussing C++ with others, or a troll. A definite NO HIRE on a team.

Member and Non-Member Functions

The C++ language provides two flavors of functions: member functions and non-member functions. A function is something which is used like this:

result = function(arguments);

By contrast, a member function is used like this:

result = object.function(arguments);

Because of this, it’s impossible to use member functions and non-member functions in the same way: where a non-member function can be called on its own (provided that you have the arguments for it), a member function also requires an object on which it is called.

The Window Procedure Problem

This can be quite confusing to beginners, for instance when defining the window procedure in the Win32 API: this requires defining a non-member function with a certain set of arguments, and then providing a function pointer (referencing that function) to the API for registering it with a window. This usually looks like this:

LRESULT CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM)
{
  // Implementation
}  

int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    WNDCLASS wc;  

    wc.lpfnWndProc = (WNDPROC) MyWndProc;  

    // Register the other WNDCLASS properties 

    RegisterClass(&wc);
}

A question that is often asked on beginner forums is, how do I use a member function of my Window C++ class as a window procedure?

This is, of course, impossible. The main reason why it’s impossible is that it doesn’t make any sense: a window procedure, in the Win32 API, is a procedure that will be called on every window of that window class. By contrast, a user-defined Window C++ class tends to have a “one instance = one window” approach to things, so that even if the same function is called for every window, the object on which it is to be called is different, leading to the question of how those objects are specified to the Win32 API.

A New Hope

Of course, the user could add the constraint “one window = one Win32 window class”, which means that a given window procedure will only ever be called for a single window (the question of whether using a window class to create a single window is an abuse of window classes is best left alone). Then, common sense would imply that a member function could be used as a non-member function as long as the object on which it is called is provided:

class MyWindowClass
{
public:
  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM)
  {
    // Implementation
  }
}; 

int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    MyWindowClass windowInstance;
    WNDCLASS wc;  

    wc.lpfnWndProc = (WNDPROC) windowInstance.WndProc;  

    // Register the other WNDCLASS properties 

    RegisterClass(&wc);
}

The hope here is that C++ will somehow detect that “object.function” can be used in the form “result = object.function(arguments)” and therefore behaves just like a normal function. Of course, this doesn’t work: C++ doesn’t support closures.

Closures

By default, a C++ function pointer (the data type used to manipulate functions beyond simply calling them right away) is just a pointer to a function. This means that it can only point at a finite set of values, which happens to be the set of all available non-member functions (of the appropriate type) within your application. It does not carry any other values.

The problem is that “object.function” is not a non-member function defined within the application: it’s a member function being applied to an object. There is no way for the compiler to detect and define this function at compile-time automatically: you could have any number of objects created and destroyed within your application at runtime, and “object.function” will do a different thing for every one of these objects (because this is how member functions work, after all: behave differently on every object).

In short, there’s no workaround for the fact that “object.function” is the association of a member function (”function”) and a piece of data (”object”), and that no built-in C++ type can store both a function and a piece of data (this is commonly known as a closure, and C++ does not support these).

Of course, since closures are a fairly useful tools, a set of replacement tools have been provided: you still can’t use a normal function pointer (or member function pointer) to represent them, but you can use another variable, or another type.

The most elementary example was known from C. C APIs that let you define callbacks usually let you define callback data as well (unless they are brain-dead, which sometimes happens with C APIs). Callback data is the “data” part of the closure, while the callback itself is the “function” part of the closure. It all starts with a callback function that takes an additional “data” argument:

void myCallback(void *callbackData)
{
  MyObjectType &object = *reinterpret_cast<MyObjectType*>(callbackData);
  object.function();
} 

MyObjectType bobby;
hypotheticalAPI(myCallback,&bobby); 

MyObjectType timmy;
hypotheticalAPI(myCallback,&timmy);

Here, the ‘hypotheticalAPI’ function stores the callback and data together, then calls the callback function with the associated data as its first argument. This means that the “myCallback” function will call either “bobby.function()” or “timmy.function()” depending on which callback is activated.

This is actually the way the Win32 API is intended to work. The difference here is that you don’t pass another argument this way, but instead associate the callback data to the handle of the window. This works more or less like this:

class MyWindowClass
{
public:
  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM)
  {
    // Implementation 
  }
};  

LRESULT CALLBACK MyWindowClassWndProc(HWND h, UINT i, WPARAM w, LPARAM l)
{
  MyWindowClass &object =
    *reinterpret_cast<MyWindowClass*>
      (GetWindowLongPtr(h, DWLP_USER)); 

  return object.WndProc(h,i,w,l);
}  

int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    MyWindowClass windowInstance;
    WNDCLASS wc;   

    wc.lpfnWndProc = (WNDPROC) MyWindowClassWndProc;   

    // Register the other WNDCLASS properties  

    RegisterClass(&wc);  

    HWND h = CreateWindow( /* args */ ); 

    SetWindowLongPtr(h, DWLP_USER, reinterpret_cast<LONG_PTR>(&windowInstance));
}

The SetWindowLongPtr function is used to associate the address of our windowInstance object to the window handle. The window procedure we register then uses the GetWindowLongPtr function to retrieve the windowInstance object, and calls its member function with the correct arguments.

Functors

Aside from the old C trick, C++ also provides the user with the ability to overload “operator()”, which means the ability to have any object behave like a function. And since objects can carry arbitrary amounts of data, having them behave like closures is a very simple task. The most naive implementation of this happens in the standard library itself: instead of having the various algorithm functions (transform, accumulate etc) take function pointers, these functions take an arbitrary type as the operation to be applied. This way, any object with a correctly implemented “operator()” can be used:

struct multiplyBy
{
  int lhs;
  int operator(int rhs) const { return lhs * rhs; }
  multiplyBy(int lhs) : lhs(lhs);
}; 

std::transform(std::istream_iterator<int>(std::cin),
               std::istream_iterator<int>(),
               multiplyBy(10),
               std::ostream_iterator<int>(std::cout,"\n"));

The implementation is quite simple: instead of defining a function pointer argument, use an arbitrary type parameter:

template<typename F>
int apply_twice(int value, F f)
{
  return f( f(value) );
} 

apply_twice(5, multiplyBy(2));
// Output : 20

However, this requires compile-time resolving of the function: since the type of the functor is a template argument, the same function template cannot be made to accept, at runtime, both a normal “int (*)(int)” function and a “multiplyBy” instance.

Boost.Function

The obvious solution, then, would be to use runtime polymorphism provided by virtual functions: make a base “function” class where “operator()” is virtual, then create a derived class template which, given a functor (or normal function pointer) wraps around that functor so that it can be used wherever the base class can. The boost library actually goes a little bit further in this respect: it provides a clean way of specifying the type of the wrapped function, and handles the memory allocation of the underlying base class, so that the functions become value types:

int apply_twice(int value, boost::function<int(int)> f)
{
  return f( f(value) );
} 

boost::function<int(int)> multiplyBy(int i)
{
  return boost::bind(std::multiplies<int>, i);
} 

apply_twice(5, multiplyBy(2));

Boost.Function also handles member functions out of the box:

struct integer
{
  int value;
  integer(int value) : value(value) {}
  int add(int other) { return value + other; }
}; 

integer i = 3;
boost::function<int(int)> add3 = boost::bind(&integer::add, i); 

apply_twice(5, add3);

The documentation for version 1.37.0 is available here :

http://www.boost.org/doc/libs/1_37_0/doc/html/function.html
http://www.boost.org/doc/libs/1_37_0/libs/bind/bind.html

Code Template Parameters

One cannot provide a function pointer as a template argument. This means that cases in which polymorphism is desirable for compile-time reasons (such as using one set of operations when testing and another set of operations when running the code), or where the behavior of code depends on a compile-time element and should be able to evolve in an open-closed fashion, cannot be handled by passing the correct function pointer.

Of course, a common trick in template metaprogramming is to replace entities which cannot be used as parameters (such as non-integer values) with types that have the entities as static members.

template <typename T>
void Frobnicate(int value) { T::Process(value); } 

struct Print
{ static void Process(int value) { std::cout << value; } }; 

struct Ignore
{ static void Process(int) {} }; 

Frobnicate<Print>(10);
Frobnicate<Ignore>(10);

As long as the structure that contains the function has external linkage (that is, it’s not defined inside a function) this will work and inject the correct kind of behavior into the function template at compile-time, possibly also performing any required inlining.

A typical application of this approach is, as mentioned earlier, unit testing: when working with rendering-related or input-related objects, it’s useful to replace their primitives with mocks that can test if the calls performed were those expected. This replacement can be done with runtime polymorphism (using an interface for the primitives, with a real class and a mock class boh implementing it) but leads to unnecessary performance loss (the overhead of runtime polymorphism that is not really required outside of the unit testing scenario). Using compile-time polymorphism based on templates, unit testing works, but the runtime code is still as optimised as if no unit testing ever happened.

Segregation is Good

As a frequent reader of the gamedev.net game development forums, I often notice that most beginner and intermediate developers start designing the architecture of their game by deciding on a base class from which all game objects will inherit, and storing a list of these objects. The justifications given are usually that:

  • It’s Object Oriented.
  • Inheriting from a base class allows code reuse.

The most appealing advantage of the “base class everything inherits from” approach is that it provides the illusion of a solid design foundation (that is essential to the “getting things done” feeling that motivates many of us) without requiring a lot of thought. All that is to be done is to slap together a few functions into a base class (usually plagiarized from one of the many tutorials available on the web) and then start inheriting.

The Issues

The naive approach to the base class solution can be summarized as this:

interface BaseObject
{
  void render();
  void update();
}

In theory, this interface seems to do everything required: after all, every object will have to update its state, and every frame it shall render itself to the screen. In practice, however, this approach leads to two serious issues:

  • Not all objects are both updated and rendered. For instance, a script or a trigger cannot be rendered, but they still have to be regularly updated. The least that could be done here is to separate the rendering side of things from the update side.
  • Sometimes, updating requires access to other objects. This happens for instance when objects collide or when an AI looks for a target. However, interacting with other objects only happens through the base object interface, which provides no information about what the other object is. Even assuming that all objects have a collision hull as part of their public interface (which in itself also does not make any sense, since many objects do not collide with anything), determining that the other object in a collision is a friend or an enemy requires knowledge beyond any acceptable base interface.

While the former can easily be solved by using two base classes instead of one, the latter is much more problematic. It is usually solved through contraptions such as downcasting (which eliminates the benefits of the Liskov Substitution Principle) or the Visitor Design Pattern (which eliminates the benefits of the Open-Closed Principle in most modern static languages).

The benefits

But surely people wouldn’t be using base classes this way if there wasn’t a tangible benefit to using them, would they? Well-known games (including the original Half Life engine, which was mod-friendly enough to give birth to a vast number of mods) have used this approach through the ages.

Purty pictar of waterfall. There is a fundamental rule for interface implementation and class inheritance:

The finality of every interface and every inheritance relationship is to allow code to operate on different types of objects.

The sole benefit of using a base class for game objects is to store those objects in a single container and apply update and render functions over that container. Everything else in a typical game requires using a more specific type through visitation or downcasting.

When, then, is a single container useful? In the case of a game engine, a single container is useful because on the one hand, it’s preferable to have the engine handle the storage, lifetime and processing of game objects and on the other hand, designing a game engine to allow the addition of other containers (one for each type of object, for instance) is difficult.

As such, having everything inherit from a single type makes communications between the engine and the game much easier (only one type of object has to be carried through the interface), even though it might make the development of the actual game harder.

Of course, a container may allow multiple interfaces to exist: a container for renderable objects, a container for updated objects, a container for objects with collision detection, a container for objects with a physical model, a container for objects which are synchronized over the network and so on. However, the original problem remains: when two objects collide, the collision response depends on the exact type of the objects, which exists in game space but not in engine space. The engine is therefore by construction unable to provide the original most derived types back to the game, and so the game must retrieve them by other means (note that visitation is not possible, because it requires to encode the possible most derived types in the visitor, which itself is encoded in the interface of the visited object.

However, beginner and intermediate programmers don’t write engines (or at least, they shouldn’t, because the motive that drives studios to write engines is the necessity to distribute programming tasks across large teams with varying competence, and to keep the code for later projects), they write games. The source code of these games is worked on by only a small handful of programmers, usually only one, which allows a far greater level of control, especially for purposes of refactoring. As such, the necessity of having generic containers disappears, and the main benefit of a single base class with it.

Segregate types

My advice is pretty simple: strive to keep one list per type of object. In your average video game, you would have a list of projectiles flying around, a list of AI-controlled opponents, and a player-controlled character.

Do not let this approach hurt code reuse, however. If both the player character and the AI-controller opponents can take damage from walking in lava, you don’t want to write the damage assignment code twice. Instead, you can have both the AI-controller opponents and the player-controlled character implement the same interface with a single “takeDamage()” function, and apply the damage assignment code to both. You may even share the health/damage handling code between the player and the opponents by aggregating a “health” class, by inheriting from a “Character” class which manages health, or by applying a “WithHealth” mix-in:

class IDamageTaker
{ public: virtual void takeDamage(int); }; 

template <typename T>
class WithHealth : public IDamageTaker, public T
{
  int health;
public:
  void takeDamage(int d)       { health -= d; }
  void healDamage(int d)       { health += d; }
  bool alive()           const { return health > 0; }
}; 

class Vanilla
{ public: virtual ~Vanilla() {} }; 

class PlayerCharacter : public
  WithHealth<
  WithPosition<Vanilla> >
{ /* Player-related data here */ }; 

class AIOpponent : public
  WithHealth<
  WithPosition<
  WithTarget<Vanilla> > >
{ /* Opponent-related data here */ };

Now, the code for health management is not duplicated and the code for assigning damage is not duplicated. The only dupicated code is the traversal of the various lists (since instead of traversing a single list, now several lists must be traversed in order to reach all elements), and that code is not only very small, but also fairly easy to factor out (for instance, by implementing an iterator that traverses several containers in order).

On the other hand, because of the presence of several lists, there is no more need for determining whether a projectile has hit an opponent or the player: the type of the object is known simply because the currently processed list is also known.

Flow

Flow is a lightweight C++ inter-thread flow library, built on top of the boost::thread library. It allows dispatch of parts of a complex computation process to one or more additional threads, in a transparent and idiomatic way. It has been written in early 2008 by me (Victor Nicollet), and it is available under the terms of the new BSD license.

The flow library implements thread-safe FIFO queues (flows), and provides facilities for manipulating them that are compatible with the Standard C++ Library.

Downloads

Using this library requires Boost.Threads and Boost.Optional to be installed and available to the program. To use the elements defined in the flow library, one only has to include the header file flow.hpp: since all code is templated, there is no need for separate compiling and linking.

  • flow.hpp : include this file to use any entity in the library.
  • prime.cpp : a naive prime number test using several cores.
  • sort.cpp : a constant-time sort using an auxiliary thread.

Concepts

A flow is a FIFO queue where enqueueing and dequeueing are atomic. The type flows::flow<T> represents a flow of elements of type T.

Flows are manipulated through readers and writers, which are objects used to read from and write to the flow. Reading will remove the oldest element from the flow, while writing will append a new element to the flow, in a FIFO fashion. Attempting to read from an empty flow will block until another thread writes to the flow. Readers are represented by class flows::reader<T>, and writers are represented by class flows::writer<T>.

When all writers of a flow disappear, the flow is closed: all the readers are notified that no more data will be appended to the flow, triggering an end-of-flow state once all the remaining elements have been removed from the flow.

When all readers of a flow disappear, the flow is silent: all the writers are notified that nobody will ever read the data written to the flow, providing opportunities for optimization.

When all readers and writers of a flow disappear, that flow is automatically garbage-collected and is destroyed by the thread that destroyed the last reader or writer (along with all the elements it still contained).

Documentation

class flows::reader<T>

This class represents a reader, which may be associated to a flow (valid reader), or not be associated to any flow (invalid reader). The class itself can be summarized as:

template <typename T>
class reader
{
public:
  typedef T                  value_type;
  typedef boost::optional<T> option_type;
  typedef /* unspecified */  iterator; 

  iterator    begin();
  iterator    end();
              reader();
              reader(const reader&);
  reader&     operator =(const reader&);
  void        close();
  option_type get();
};

The default constructor creates an invalid reader. A valid reader can only be obtained from flows::flow<T>. Assigning to a reader dissociates that reader from its flow (if any), which may lead to that flow being silenced or even destroyed if this was the last reader for that flow. Note that flows::reader<T>::close() is equivalent to assigning a default-constructed reader: the reader becomes invalid and detached from its associated flow (if any).

The flows::reader<T>::get() function behaves as follows:

  • If the reader is invalid, returns no value.
  • If the reader is valid, but the associated flow is closed and empty, returns no value.
  • If the reader is valid, but the associated flow is empty, blocks until a value becomes available or the flow is closed, and tries again.
  • If the reader is valid and the associated flow is not empty, atomically removes the oldest value and returns it.

As a consequence, if two or more readers are associated to the same flow, every element in the flow will be read by at most one reader (and all elements will be either read by a reader or destroyed along with the flow).

flows::reader<T>::begin() and flows::reader<T>::end() are the first and past-the-end iterators of the read sequence of elements. They are input iterators (in the sense defined by the Standard C++Library) which represent the sequence of elements read by a particular reader:

  • Creating an iterator using begin() or incrementing an iterator reads the next value from the flow by calling the flows::reader<T>::get() function on the associated reader. This function call may block until the flow is written to. If it returns a value, then the iterator is bound to that value. Otherwise, the iterator becomes equal to the past-the-end iterator.
  • Dereferencing an iterator returns the value bound to the iterator. This is guaranteed to occur in constant time.

Iterators are invalidated on every assignment to the reader.

An analogy for read iterators is the std::istream_iterator, but the data is read from a flow using flows::reader<T>::get(), instead of being read from a stream using operator>>().

class flows::writer<T>

This class represents a writer, which may be associated to a flow (valid writer), or not be associated to any flow (invalid writer). The class can be summarized as:

template <typename T>
class writer
{
  typedef T                 value_type;
  typedef /* unspecified */ iterator; 

  iterator begin();
           writer();
           writer(const writer&);
  writer&  operator =(const writer&);
  void     close();
  bool     silent();
  void     put(const T&);
};

The default constructor creates an invalid writer. The only way to create a valid writer is to use flows::flow<T>. Assigning to a writer dissociates that writer from its flow (if any), and then binds it to the flow of the writer that was assigned to it (if any). This may lead to the flow becoming closed or even garbage-collected. flows::writer<T>::close() is equivalent to (but more idiomatic than) assigning a default-constructed writer.

The flows::writer<T>::put() function atomically writes a copy of its argument to the flow associated to the writer. If there is no associated flow, the behavior of this function is undefined.

The flows::writer<T>::silent() function returns whether the associated flow is silent or not. If there is no associated flow, the behavior of this function is undefined. This is provided as optimization hints to avoid computing values only to place them in a silent flow. It can be used to notify search threads that the one of them has found what was searched. See the above example on prime numbers for an illustration.

The flows::writer<T>::begin() function returns the output iterator for this writer. This iterator behaves as an std::back_insert_iterator, but calls flows::writer<T>::put() on its associated writer instead of calling insert(). This iterator is invalidated by assignment to the writer.

class flows::flow<T>

This class represents an active flow, and allows creating fresh readers and writers associated to that flow. For that reason, for as long as this instance exists, the underlying flow can be neither closed nor silenced (because a new reader or writer could be obtained from it at any time). Therefore, this instance should be used to prepare a computation, and destroyed before the computation starts.

When the instance is destroyed, the flow itself remains in memory for as long as readers or writers are associated to it. Once all readers and writers are gone, the flow is destroyed immediately, destroying any unread data left.

Note that the library provides several functions that dispatch computations to other threads without requiring the explicit creation of a flow from user code. Ideally, flows::flow<T> should only be used in situations where these functions do not meet the needs of the program, and even then it should only be used with care.

The class can be summarized as:

template <typename T> 
class flow
{
  flow(); 

  const writer<T>& input() const;
  const reader<T>& output() const;
};

As expected, flows::flow<T>::input() returns a writer associated to the flow, and flows::flow<T>::output() returns a reader associated to the flow. Unlike the naming approach of the C++ Standard Library, where an input stream is a reader and an output stream is a writer, the input of a flow is the writer (where the flow gets its input) and the output of a flow is the reader (where the flow sends its input).

Generators

A generator is a separate thread that computes values and outputs them to a flow. The original thread keeps a reader associated to that flow, and may read values from the flow as they become available.

Two functions allow the creation of generators:

template <typename T, typename F>
reader<T> generate(F f); 

template <typename T, typename F, typename I>
reader<T> generate(F f, I b, I e);

The first function creates a new flow and a new thread. Then, in that new thread, it calls f(w) where f is the argument to the generate function, and w is a writer associated to that flow. Simultaneously, it returns a reader associated to the flow in the original thread. The created thread ends when the argument function returns.

The second function creates one new flow, and creates a thread for each iterator i between b and e. Each thread calls f(w,*i), and the function simultaneously returns a reader for the flow. Each created thread ends when its function call returns.

That is, the first function creates a generator, and the second function creates one generator for each iterator in the passed sequence.

Processing

A processor is a thread which reads from a flow, does some computations, and writes to another flow. The most generic way of doing this (by specifying the exact function that reads and writes) is with the flows::process<T>() function:

template<typename T, typename U, typename F>
reader<T> process(const reader<U> &source, F f);

This function creates a new flow and a new thread which runs f(source,dest), where dest is a writer associated to the new flow. It immediately returns a reader associated to the new flow.

A special case of processing is mapping an function to a flow: the processor reads a value, applies a function to it, and writes the result to another flow. Mapping is done using the flows::transform<T>() function:

template <typename T, typename U, typename F>
reader<T> transform(const reader<U> &source, F f, unsigned n = 1);

This function creates n new threads and a single flow, and returns a reader associated to that flow. Every thread reads a value x from the source reader, and writes f(x) to the new flow. Note that if n = 1, the order is preserved, but not if n > 1. The new flow is closed when all the data from the original flow has been processed.

Accumulating

An accumulator is a thread which reads from a flow and applies a binary operation to collapse all the values into a single one, using an initial value for the first application. Once all the data is processed, it writes the final value to an output flow.

Accumulation is performed using the function flows::accumulate<T>() function:

template <typename T, typename U, typename F>
reader<T> accumulate(const reader<U> &source, T initial, F f);

This function creates a flow and thread. The thread performs the operation f(initial,*it) for it between source.begin() and source.end(), then writes initial to the flow. The function returns the reader associated to the flow immediately.

Further work

The implementation could be improved. First, it could be adapted to work with lock-free structures. Second, it could also be adapted to use worker threads instead of spawning new threads for every operation.

The interface could also use some improvement. For instance, it’s still too easy to create deadlocks by forgetting to close a writer in the wrong place. And the code does not interact with the standard library as well as it should.

Iterator Intervals

Implicit Iterator Intervals

The Standard C++ Library is built around the concept of iterators. On the one hand, output iterators can be incremented and assigned values, and on the other hand input iterators traverse a range between a start iterator (usually referred to as the begin iterator) and a past-the-end iterator (the end iterator). All containers follow this convention, either through member functions begin() and end() or through pointer arithmetics based on base pointer and size. Also, several other range concepts (for instance, input from an istream)  also follow this convention.

On the other hand, all standard library algorithms work on iterator ranges, which are passed implicitly by providing the two iterators independently.

The problem with implicit iterator intervals is that they don’t play nice with functions that transform intervals: for instance, a filter function would turn an interval into the elements of that interval which satisfy a certain predicate, or a sub-interval function would restrict iteration to a fixed contiguous sub-interval. In the current situation, since it’s not possible to dispatch the result of a single function call to two arguments (the expected begin and end iterators), the result of filter or sub-interval functions has to be stored as a variable, which implies that the type has to be explicitly spelled out (and it’s often too complex to write down).

Explicit Iterator Intervals

Instead of having algorithms operate on two argument iterators, I propose to combine the two iterators into a single object, called an iterator interval. The type of this iterator interval is unspecified: expression templates are used to avoid unnecessary recourse to runtime polymorphism. The only constraint is that an iterator interval must specify at least the following expressions

T::iterator is an input iterator. Then, given const T t :
t.begin() is the first iterator in the interval.
t.end() is the past-the-end iterator in the interval.

Note that this rules out the standard library containers as intervals: these will return a const_iterator instead of a normal iterator. This is because a container is not an interval, it merely has an interval that represents all its content. The mutability of a container determines the mutability of its members, whereas the mutability of an interval does not affect the mutability of the elements of the represented sequence.

For starters, a few helper functions that create intervals from most things which can have intervals:

namespace interval
{
  namespace detail
  {
    template<typename It>
    class interval_type
    {
      It begin_iterator, end_iterator;
    public:
      interval_type(It begin, It end)
        : begin_iterator(begin), end_iterator(end) {} 

      typedef It iterator; 

      iterator begin() const { return this -> begin_iterator; }
      iterator end() const { return this -> end_iterator; }
    };
  } 

  template<typename T, std::size_t N>
  detail::interval_type<T> of(T (&array)[N])
  {
    return detail::interval_type<T*>(array, array + N);
  } 

  template<typename It>
  detail::interval_type<It> of(It begin, It end)
  {
    return detail::interval_type<It>(begin,end);
  } 

  template<typename T>
  detail::interval_type< std::istream_iterator<T> > of(std::istream &in)
  {
    return detail::interval_type< std::istream_iterator<T> >
      (std::istream_iterator<T>(in),
       std::istream_iterator<T>());
  } 

  template<typename T>
  detail::interval_type< typename T::const_iterator > of(const T &t)
  {
    return detail::interval_type< typename T::const_iterator >
      (t.begin(), t.end());
  } 

  template<typename T>
  detail::interval_type< typename T::iterator > of(T &t)
  {
    return detail::interval_type< typename T::iterator >
      (t.begin(), t.end());
  }
}

So, to create an interval from a container, you can write interval::of(my_vector), to create one from an array you can write interval::of(my_array), and to create one from an input stream you can write interval::of<Type>(my_stream). Once you have obtained an interval, you can start using it.

Algorithms

For the purposes of this article, only two elementary algorithms have been rewritten. One could consider rewriting others as well, using the same principle. The key of rewriting algorithms is to have them take a single iterator interval instead of two iterators.

namespace interval
{
  template<typename I, typename It>
  void copy(const I &i, const It &o)
  {
    std::copy(i.begin(), i.end(), o);
  } 

  template<typename I, typename F>
  void for_each(const I &i, const F &f)
  {
    std::for_each(i.begin(), i.end(), f);
  }
}

So, now, it’s possible to write code such as:

interval::copy(interval::of<int>(std::cin), std::back_inserter(my_vector));

Filtering

The real benefit of using intervals is that now intervals can be transformed. An example transformation is to eliminate the elements in an interval which do not satisfy a certain predicate. This involves defining a new iterator type which wraps around the old one, but which will advance internally so that it always references a value which satisfies the predicate. The obvious limitation is that all iterators become forward iterators (the random access property, if present, cannot be kept).

namespace interval
{
  namespace detail
  {
    template<typename It, typename T>
    class filtered_interval_iterator
    {
      It internal;
      const T *owner; 

      void advance()
      {
        while (this -> internal != this -> owner -> end_iterator
               && ! this -> owner -> filter(* this -> internal))
          ++ this -> internal;
      } 

    public: 

      typedef typename std::iterator_traits<It>::value_type value_type;
      typedef typename std::iterator_traits<It>::reference reference;
      typedef typename std::iterator_traits<It>::pointer pointer;
      typedef typename std::iterator_traits<It>::difference_type difference_type;
      typedef std::input_iterator_tag iterator_category; 

      filtered_interval_iterator(It internal, const T &owner)
        : internal(internal), owner(&owner)
      { this -> advance(); } 

      filtered_interval_iterator &operator++()
      {
        ++ this -> internal;
        this -> advance();
        return *this;
      } 

      filtered_interval_iterator operator++(int)
      {
        filtered_interval_iterator temp(*this);
        ++ *this;
        return temp;
      } 

      reference operator*() const { return *this->internal; } 

      bool operator == (const filtered_interval_iterator &o)
      {
        return this -> internal == o.internal;
      } 

      bool operator != (const filtered_interval_iterator &o)
      {
        return this -> internal != o.internal;
      }
    }; 

    template<typename It, typename F>
    class filtered_interval_type
    {
      F filter;
      It begin_iterator, end_iterator; 

      friend class filtered_interval_iterator<It,filtered_interval_type>; 

    public: 

      filtered_interval_type(It begin, It end, F filter)
        : filter(filter), begin_iterator(begin), end_iterator(end) {} 

      typedef filtered_interval_iterator<It,filtered_interval_type> iterator; 

      iterator begin() const
      {
        return iterator(this -> begin_iterator, *this);
      } 

      iterator end() const
      {
        return iterator(this -> end_iterator, *this);
      }
    };
  } 

  template<typename I, typename F>
  detail::filtered_interval_type<typename I::iterator,F> filter(const I &interval, F flt)
  {
    return detail::filtered_interval_type<typename I::iterator,F>
      (interval.begin(), interval.end(), flt);
  }
}

Filtering takes an interval and a predicate, and filters the interval with the predicate, resulting in a new interval. So, to print to standard output all even numbers read from standard input:

bool even(int x) { return x%2==0; } 

interval::copy( interval::filter( interval::of<int>(std::cin), even ),
                std::ostream_iterator<int>(std::cout, "\n"));

Sub-intervals

Another functionality that can be easily implemented is the ability to select only a subset of an interval. The implementation increments the begin-iterator until it reaches the start distance, then forces any iterator which has moved the total length to equal the past-the-end iterator to mark the end of the interval.

namespace interval
{
  namespace detail
  {
    template<typename It>
    class sub_interval_iterator
    {
      It internal;
      typename std::iterator_traits<It>::difference_type left; 

    public: 

      typedef typename std::iterator_traits<It>::value_type value_type;
      typedef typename std::iterator_traits<It>::reference reference;
      typedef typename std::iterator_traits<It>::pointer pointer;
      typedef typename std::iterator_traits<It>::difference_type difference_type;
      typedef std::input_iterator_tag iterator_category; 

      sub_interval_iterator(It internal, difference_type left)
        : internal(internal), left(left)
      { } 

      sub_interval_iterator &operator++()
      {
        -- this -> left;
        ++ this -> internal;
        return *this;
      } 

      sub_interval_iterator operator++(int)
      {
        sub_interval_iterator temp(*this);
        ++ *this;
        return temp;
      } 

      reference operator*() const { return *this->internal; } 

      bool operator == (const sub_interval_iterator &o)
      {
        return this -> left == 0 && o.left == 0
          || this -> internal == o.internal;
      } 

      bool operator != (const sub_interval_iterator &o)
      {
        return this -> internal != o.internal
          && this -> left != o.left;;
      }
    }; 

    template<typename It>
    class sub_interval_type
    {
    public:
      typedef typename std::iterator_traits<It>::difference_type distance;
    private:
      distance length;
      It begin_iterator, end_iterator;
    public:
      sub_interval_type(It begin, It end, distance start, distance length)
        : length(length), begin_iterator(begin), end_iterator(end)
      {
        while (start > 0 && begin != end) { --start; ++begin; }
        begin_iterator = begin;
      } 

      typedef sub_interval_iterator<It> iterator; 

      iterator begin() const
      {
        return iterator(this -> begin_iterator, this -> length);
      } 

      iterator end() const
      {
        return iterator(this -> end_iterator, 0);
      }
    };
  } 

  template<typename I>
  detail::sub_interval_type<typename I::iterator>
  sub(const I& i, typename I::iterator::difference_type start, typename I::iterator::difference_type length)
  {
    return detail::sub_interval_type<typename I::iterator>(i.begin(), i.end(), start, length);
  }
}

With this function, one can specify the start and length of the sub-interval, just like with a typical sub-string function.

Assignment

How to assign an interval to a container? Containers have constructors and assignment functions that work on two iterators, not a single interval. However, it’s possible to work around this, in part, by using a cast function:

namespace interval
{
  namespace detail
  {
    template<typename I, typename C>
    struct assign_type
    {
      I i;
      assign_type(const I &i) : i(i) {}
      operator C() const { return C(i.begin(), i.end()); }
    };
  } 

  template<typename C, typename I>
  detail::assign_type<I,C> assign(const I &i)
  {
    return detail::assign_type<I,C>(i);
  }
}

The return value of the assignment function above can now be assigned to the appropriate container.

The final example reads even integers from standard input, stores them in a vector, then outputs all the contents of the vector between index 2 and index 12:

bool even(int i) { return i % 2 == 0; } 

int main()
{
  std::vector<int> values = interval::assign< std::vector<int> >
   ( interval::filter ( interval::of<int>(std::cin), even )); 

  interval::copy
   ( interval::sub( interval::of(values), 2, 10 ),
     std::ostream_iterator<int>(std::cout, "\n") );
}

Possible extensions

It is currently not possible to retrieve the original iterator, but this could be done easily (just extend the interval type to handle this) and would be useful (for instance when using std::find across an interval).  Also, iterator types are not conserved: filtering conserves bidirectional iterators and sub-interval extraction conserves random access iterators (plus, on random access iterators, sub-interval extraction is much easier than the above version, which has to handle forward iterators).

An Introduction to C++ Pointers

This entire text was originally part of a post I made on the GameDev.Net forums, which I’ve reformatted slightly. It exposes what is in my opinion a good explanation of what C++ pointers are and what they can be used for, starting with the elementary concepts required to introduce the hellish semantics that they provide. Of course, this article in itself is no match for starting programming with a language that uses reference semantics, but it’s still a good starting point.

Without any more discussion, here is the explanation:

Values

C++ programs manipulate values. Typical values include integers, such as 42, characters, such as ‘x’, objects of more complex types, such as std::string or std::fstream, and also instances of any class you define in your program.

Variables and References

Values need to be manipulated, which involves giving them a name. A reference is a name given to a value. Creating a reference is done like so:

Type & name = value;

Where value is usually the return value of a function or operator…

std::ostream &o = (std::cout << "Text.");

…but might also be another name given to the same value:

std::ostream &o = std::cout;

Another way to create a reference is as a function argument:

void foo(Type & name)

This will cause the value which was passed as argument to be available under that name in the entire function body. This can be quite useful if you wish to modify that value.

Of course, almost any program needs to create values. In C++, values are always created using operator new (except for literals such as 42 or “Hello”, which simply exist). operator new exists in several versions. The default version generates dynamic values, which exist until delete is called:

int & value = * new int;
value = 10;
std::cout << value;
delete (&value);

This causes performance problems if used too often, because dynamic memory allocation is slow in a non-garbage-collected language like C++. This is why another, faster version exists: placement new creates a new value using existing memory. Of course, the lifetime of the value is then limited by the lifetime of the memory which was used to create it, and it must of course be manually destroyed by calling its destructor:

std::string & str = * new (existing_memory) std::string("Hello");
str += " world!";
std::cout << str;
str.~string();
// existing_memory dies somewhere after this line

The existence of placement new allows the programmer to use memory areas which are faster than the free store used by the default operator new: it may use stack memory, a specially reserved portion of global memory, or a subset of the memory used by another value, by increasing speed of allocation. For instance, using stack memory:

 int & value = * new (alloca(sizeof(int))) int;

Since allocating objects on the stack, in global memory or as a subset of an object is a very repetitive task which involves obtaining the memory, computing the size to be allocated, and then calling the destructor of the object right before the memory is gone, the C++ language provides shortcuts to do this. Take for example stack allocation of a string:

void sayhello()
{
  std::string & str = * new (alloca(sizeof(std::string))) std::string("Hello");
  str += " world!";
  std::cout << str;
  str.~string();
}

I have underlined the repetitive tasks that are related to stack allocation. The shortcut provided by C++ in this situation is as follows:

void sayhello()
{
  auto std::string str("Hello");
  str += " world!";
  std::cout << str;
}

The main differences here are the presence of the auto keyword, the absence of the & in the definition of the reference, and the absence of the str.~string() destructor call at the end of the function. The first two differences cause C++ to allocate a new block of memory on the stack (auto) which will be released when the function returns and initialize it with a new value from the string literal “Hello”. The auto keyword also causes the compiler to generate destructor calls: the object will be automatically destroyed right before the function exits (since that is when the stack allocation is released). In this situation auto is aptly named a storage specifier.

The other storage specifier is static, which uses global memory: defining a local variable as static causes the compiler to allocate some memory for it as part of the global data span (at compile-time) and then initialize the value at that spot in memory the first time the variable’s definition is encountered. Since auto is the default storage specifier, it is generally omitted from the definition, which leads to the typical variable definition that most C and C++ programmers are used to:

std::string str("Hello");
str += " world!";
std::cout << str;

Variables at global scope automatically use global storage.

Member variables of structures or classes use the third type of allocation: they use a bit of reserved memory that was part of the value of which they are a member, and they are initialized there as part of that value’s constructor. Their destructor is automatically called as part of the value’s destructor. Before:

struct super
{
  std::string & str;
  some_memory_buffer;
  super() : str(* new (some_memory_buffer) std::string) {}
  ~super() { str.~string(); }
};

After:

struct super
{
  std::string str;
  // No explicit memory buffer
  // Automatic construction
  // Automatic destruction
};

To summarize: references are names given to values. C++ provides special shortcuts to create a value and bind it to a reference at the same time, with special rules about when the created value is to be destroyed.

Iterators and Sequences

A sequence is, as its name hints at, a sequence of values. It could be, for instance, the sequence 1, 2, 3, 4. Or, it could be the set of opponents in a video game, in an arbitrary order. Or, it could be the sequence of characters being read from std::cin. In short, sequences are the fundamental concept used to represent groups of objects that are to be manipulated together.

A typical representation of sequences is through iterators, which are means of iterating over a sequence (accessing its elements in order). The basic operations required to iterate are the ability to read the “current value”, the ability to move on to the “next value”, and the ability to determine if the end of the sequence was reached and there are no values left. For instance, pseudocode to add together values of a sequence through iteration:

a = 0
while not end-of-sequence(iter)
  a += value(iter)
  iter = next(iter)

Various languages provide various forms of iterators, but the three operations outlined above are always present. For instance, Objective Caml uses (it = []), List.hd it and List.tl it as the end-of-sequence, value and next operations. C++ uses it == end, *it and ++it as the end-of-sequence, value and next operations. So, C++ code to add together the values of a sequence (represented by two iterators of type Iter representing the first iterator of the sequence and the first iterator past the sequence) would be:

template<typename Iter>
int sum(Iter begin, Iter end)
{
  int a = 0;
  while (begin != end)
  {
    a += *begin;
    ++begin;
  }
  return a;
}

The begin-end representation of sequences is standard. The end iterator is the first iterator after the sequence: as such, it has no associated value, and trying to obtain the iterator after end is invalid. So, you cannot *end or ++end. You can, however, compare end with another iterator to see if that other iterator has reached the end of the sequence.

The point of using a past-the-end iterator (one that isn’t in the sequence, but is actually right after it) instead of a last-element iterator (one that corresponds to the last element in the sequence) is twofold. First, it makes code less complex, because the condition “I have reached the past-the-end iterator on this iteration” is easier to evaluate than “I was working on the last iterator on the previous iteration”. Second, it allows representation of empty sequences (since the empty sequence has no last element and as such could not be represented using a last-iterator approach).

An iterator which supports only *it and ++it is called a forward iterator. Some iterators also support –it (which moves to the previous element), making it a bidirectional iterator. Some iterators also support it + n and it – n, allowing the iterator to move an arbitrary number of steps backward or forward in a single jump, which is called a random access iterator. Iterators may in turn be read-only (input iterator), write-only (output iterator) or support both read and write.

Iterators are a very powerful concept: most of the things in C++ which look like sequences can be turned into iterators.

  • The sequence of elements in a vector is represented by vect.begin() and vect.end(), which are random access read-write iterators (or read-only, if the vector is constant).
  • The sequence of elements in a list is represented by list.begin() and list.end(), which are bidirectional read-write iterators (or read-only, if the list is constant).
  • The sequence of objects of type T read from an std::istream such as std::cin is represented by std::istream_iterator<T>(std::cin) and std::istream_iterator<T>() (past-the-end iterator) which are forward input iterators.
  • Adding a sequence of elements at the end of any non-associative standard library container c is represented by std::back_inserter(c), with no end iterator (this could be an infinite sequence) and is a forward output iterator.

The list goes on and on. This system is then combined with iterator-based algorithms, such as std::copy(src_begin, src_end, dest_begin), where src_begin and src_end are at least forward input iterators representing the input sequence to be copied, and dest_begin is at least a forward output iterator representing where the input sequence should be copied to. As such, reading as many integers as possible from standard input and placing them in a vector is as simple as:

std::vector<int> integers;
std::copy( std::istream_iterator<int>(std::cin),
           std::istream_iterator<int>(),
           std::back_inserter(integers) );

Or, we could add together the values read on the standard input using our function above:

std::cout << sum( std::istream_iterator<int>(std::cin),
                  std::istream_iterator<int>() );

Just like we could add together the elements of a vector:

std::cout << sum( integers.begin(), integers.end() );

Pointers

Pointers are a concept originally introduced in C. From a semantic point of view, pointers are random access read-write iterators. As iterators, they represent sequences of contiguous elements of the same type—such sequences are created either using a vector, or using a block allocation approach such as new[] or arrays.

Given a block of N objects of type T, a pointer representing that sequence is of type T*.

Depending on the nature of the block, obtaining the first pointer begin in the sequence varies.

  • T *begin = new T[N]; will directly return the first pointer in the sequence.
  • If a is an array of N objects of type T then T *begin = a; will create the first pointer in the sequence of elements of a.
  • Otherwise, if t (of type T) is the first element of a sequence (as opposed to the first iterator of a sequence), then T *begin = &t; is the first iterator of the sequence.

The past-the-end iterator of a sequence is simply defined as T *end = begin + N;

int values[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::cout << sum(values, values + 10);

As with any other iterator, going beyond the bounds of a sequence (before begin or after end) results in undefined behavior, which will usually lead to random misbehavior of your program.

All of the above also holds when N = 1 (which means that a single object is also a one-object sequence, which can as such be manipulated using a pointer).

The main problem with pointers is that this is not everything. If pointers were merely iterators, then people would have no more trouble with them than they would have with the other iterators in the standard library. However, pointers were introduced in the C language as a means to represent several other concepts.

The first of these concepts is reference semantics. You see, in C, there are no references per se: every time you create a variable, it also creates a value. This makes it difficult to handle dynamic memory (because every variable you create already has its own value, so how do you give your dynamic memory a name in order to use it?) and allow functions to modify a variable in another function (because all the arguments to your function are, by default, brand new values that will disappear when the function returns, and you have no access to the values in the calling function). The solution adopted was to decide that, since pointers are read-write iterators, and every value is a one-element sequence by definition, then pointers can be used to give indirect names to values.

For instance:

 /* Solve aX² + bX + c */
int find_solutions(float a, float b, float c, float *x1, float *x2)
{
  float delta = b * b - 4f * a * c;
  float sq;  

  if (delta < 0f)
    return 0;
  sq = sqrt(delta);
  *x1 = (- b - sq) / (2 * a);
  *x2 = (- b + sq) / (2 * a);
  return 2;
}

Important note: the above is a C function which uses idioms not found or advised in C++ code. The C++ equivalent would use references instead of pointers, and would probably return a boost::optional<std::pair<float,float>> anyway.

This function needs to return the number of solutions (zero or two), but it also needs to send back the values of those solutions. In order to do so, it uses a trick which consists in being given two iterators to one-value sequences and modifying the unique value in each sequence. Since a copy of an iterator of a sequence is a new iterator of that same sequence, the iterator allows the function to modify the original sequence—and the values inside that sequence are the values from within the calling function.

int main()
{
  float x1, x2;
  float *px1 = &x1; // An iterator to the one-element sequence 'x1'
  float *px2 = &x2; // An iterator to the one-element sequence 'x2'  

  find_solutions(1f, 0f, -1f, px1, px2);   

  // The function call changed the contents of the sequences
  // iterated by px1 and px2, namely x1 and x2. As such, the
  // values of x1 and x2 have been changed.
}

Of course, C++ provides references, which is why pointers are not used for pass-by-reference in C++ at all (as references provide a far more simple representation of one-element sequences).

Another use of pointers, which remained in C++, is the representation of reseatable references. In C++, a reference is a name given to a value, and the value is bound to the name forever. It is not possible to bind the name to another value (though it is possible, of course, to bind several names to the same value). Reseating a reference means binding it to another value, and is possible in languages such as C# or Java, but not in C++.

However, pointers are merely iterators, and it’s possible to assign an iterator to another (thereby changing the sequence that the iterator is traversing, or the point in the sequence where the iterator is)—after all, this is the entire point of traversing a sequence with a single iterator!

Therefore, when it becomes useful to have a reference to a value, but the ability to change that value is also useful, people sometimes use a pointer (though, in modern C++, there are other types, such as boost::shared_ptr or boost::weak_ptr, which do a far better job). For instance, if you wish to reference a fighter’s target (and fighters can change targets at will):

struct fighter
{
  object *target;
}

As such, a fighter’s target can be changed by changing the pointer so that it corresponds to another value instead of the original one.

A third use of pointers, introduced in C, was optional semantics. An option type allows the possibility for a value to be absent. For instance, one could decide that sqrt returns a float option: either its argument is positive and it returns a float, or it is negative and then it returns nothing.This is quite similary to the option types found in ML languages, for instance Objective Caml’s ‘a option.

Instead of defining an option type distinct from an iterator type (as C++ does for all its iterators), C merged the two together, and this carried over to C++. A pointer can be constructed from the integer constant zero, and thus becomes the null pointer. This is a compile-time effect: the compiler notices that you’re assigning zero to a pointer, and transforms that integer into the actual value of the null pointer (which may be something entirely different from zero).

The null pointer may not be used in any way (increment, decrement, arithmetic, dereferencing), except to be compared for equality with another pointer, to be assigned a new pointer, or to be tested as a boolean condition (a null pointer always evaluates to false, while other pointers evaluate to true).

To summarize: pointers are bidirectional read-write iterators used in C for reference semantics and reseatable reference semantics, as well as a clunky option type.

Array iterators

Array, pointers and iterators

Consider a typical operation of outputting an array of data to the screen:

const char *users[] = { "Alice", "Bob", "Charlie" }; 

for(int i = 0; i < 3; ++i)
  std::cout << users[i] << "\n";

This can be performed in a more functional way by using algorithms and iterators:

std::copy(users, users + 3,
          std::ostream_operator<const char*>(std::cout, "\n"));

While marginally longer, this code has the advantage that the output iterator can be replaced with any other (for instance, one that appends to a vector). This relies on the fact that arrays decay to pointers when they are used in a pointer context (be aware that arrays are not pointers, however) and that pointers are iterators.

The main issue, however, is the compile-time constant 3 which represents the size of the array. Should the contents of the array change over time, one may forget to update the constant (even if it’s defined as a named constant on the line that immediately follows the array).

Arrays as template parameters

Luckily, it’s possible to solve this problem by using a template function to extract the size of an array (since the size of the array is part of its type). The code and application:

template <size_t N, typename T>
size_t size(T (&)[N]) { return N; } 

std::copy(users, users + size(users),
          std::ostream_operator<const char*>(std::cout, "\n"));

This works by having a template function that has both the type and the size of an array as template parameters. Since the template parameters are inferred (when possible) from the types of the arguments provided to the function template, both the type (which is ignored) and the size are extracted from an array reference. Even better, unlike the brittle sizeof(users)/sizeof(users[0]) construct, this code will throw a clean compile-time error if for some reason users becomes a pointer and the size is not available anymore.

The next step is obviously:

template <size_t N, typename T>
T* end(T (&a)[N]) { return a + N; } 

std::copy(users, end(users),
          std::ostream_operator<const char*>(std::cout, "\n"));

C++ Warts

What warts are

Warts, in programming jargon, refer to any information appended to a symbol’s name in addition to the core semantic name of that symbol, usually in a highly abbreviated and standardized fashion. Examples of wart-bearing names (with the warts in red) would be lpszName, CUserSocket, g_project_config, author_t, and next_. In themselves, warts are just a way of conveying additional information about a symbol, usually a property such as its kind (class, template, interface), type (long pointer to a string), scope (global or member) or some more specific information (encoding, being a row or column index, and so on).

Warts fall into three major categories:

  • Useful, these convey a relevant information that would not be easily conveyed otherwise.
  • Useless, these convey some information that can be readily gathered from the name or the usage.
  • Useless and dangerous, these convey some information with some negative side-effects on code quality.

Those that are Useful

To be useful, a wart must be small enough to avoid cluttering the name (most people consider the clutter limit to be at most one character long), summarize a piece of information that is not obvious from the context of use (and cannot be made obvious by using the language), and provide a large enough level of understanding that it can severely influence the plans of the programmer.

The canonical example of an useful wart is the “interface” wart, which consists in prepending an uppercase i (for interface) to the name of an interface (or, in C++, an abstract class which serves as an interface). The message conveyed is that the symbol represents a type which provides no functionality, and merely defines a list of methods that must be provided by any subtype. There is a big difference between a function with a signature such as:

void Print(const Formatter &fmt)

And a function with a signature like:

void Print(const IFormatter &fmt)

The first function brings up the idea that an instance of the codebase-provided Formatter class must be created, customized either through constructor arguments or through member functions, and then passed to the function. The second function brings up the idea that one must instead use an existing implementation of the formatter, or perhaps create a new one. Of course, the wart somewhat loses its usefulness when inside code, because an intellisense-like tool can easily convey the same information. However, in documentation summaries or samples, or when working on the white board, these are useful.

Those that are useless, but benign

The leading contenders here would be the C prefix (indicating that a type is a class), the T prefix (indicating that a symbol is a template), the _t suffix (indicating that a symbol is a type), the g_ and m_ prefixes (indicating respectively that a symbol is a global or member variable). The latter is sometimes found as a trailing underscore.

All of this information can either be clearly inferred from the context in any reasonably well-written program (not only should all programs be well-written, but programs which use warts generally use them in order to write the program well), or provide no actual relevant information.

The starting point would be the C prefix. Indicating that a symbol is a class type can serve two purposes: differentiating it from non-class types, and differentiating it from non-types. The first distinction is pointless: the only situation when a class behaves differently from another type in a way that actually matters is when looking at PODs (and even then, classes can be PODs as well) and code that relies on that distinction is extremely rare.

As for labeling types to differentiate them from variables, this is a good idea in C, where no C++ namespaces exist and thus collisions must be avoided between type names and variable names. In C++, however, most serious projects place their types into namespaces, and the global namespace can be used as a last resort if necessary. Furthermore, even though it can be easily solved, ambiguity between type names and other symbols arises only with a high rarity anyway.

The T prefix to templates may appear as a good idea in the same way as the I prefix. However, a template is nothing more than an ad hoc meta-function which uses ‘<>’ instead of ‘()’ for its parameter list. As such, there is no more need to differentiate templates from non-templates than it is to differentiate functions from non-functions: the template parameter list is almost always present on a template (removing any ambiguity), and the only case where it is not present is when passing the template as an argument to another template, a situationboth too rare and too complex to be resolved without knowing what the other template is doing.

The g_ prefix for global variables does provide information that is relevant and important. However, it can be easily gathered from the context in a well-written program, simply by namespacing it: a namespaced variable is always obviously distinct from a local or member variable. The advantage of adding the namespace prefix is that the ownership of the global variable is more clear (since the namespace will reflect which part of the program the global belongs to, if any), and the prefix can be ignored easily in a context where it is obvious that a global variable is being manipulated. Also, using global variables in C++ is a typical recipe for disaster (in particular because of order-of-initialization problems) and is usually replaced by a global function returning a reference to an internally managed global object instead, making this point more of a historical anecdote.

The m_ prefix (or underscore suffix) for member variables is also useless: the vast majority of uses of a member variable happens in a context where the nature is a syntactical fact (such as object.member, object -> member or constructor() : member(data)) where a wart is entirely useless. The situation where ambiguity can arise is when accessing a member variable in a member function. Two possibilities exist here: either the function is small enough that the variable, being neither a local variable nor a function parameter, is necessarily a member, or the function is large enough to warrant an effort. This can be done by prepending a this -> to the variable name, which serves the same purpose as a wart, but has the advantage of being removable when unnecessary.

Those that are useless and dangerous

Worse that being useless, is being dangerous. Most useless warts carry redundant (and thus useless) information by using up only one or two characters. Some warts, however, can carry incorrect information, use up too much space, or even prevent code from being portable.

Correct information appears mostly with warts that carry type information. During the lifetime of a program, it’s possible for the type of variables to change to accomodate program extensions or bug corrections. Expecting the programmer doing the modification to also propagate the name change is a good idea in theory, but hopeless in practice. Inevitably, out of laziness, honest mistake or looming deadlines, the type wart will become obsolete, and will lead a maintenance programmer into thinking that iLength is an integer when in fact it is a floating-point number.

Using too much space becomes a real difficulty with type warts: either class instances get useless warts such as ‘o’ or ‘obj’ to indicate that they are objects (which is a quite pointless fact in object-oriented software), or they get more detailed ones. This is to say nothing of the typical long-pointer warts so widespread in the Win32 C API (meet the lplptstrUsername internationalization-friendly pointer to an username). While in itself just a readability issue of making variable names longer, these warts often lead the programmers to shorten the non-wart part of the name to keep line lengths manageable, leading to lplptstrUsrnm or worse.

Last but not least, there is the case of the prefix underscore: when an identifier begins with an underscore followed by a capital letter, that identifier is reserved by the implementation. This means that code can break when changing compilers or compiler versions.

Conclusion

While warts are not always necessarily bad, many are completely useless, requiring additional uniformization effort for no real gain besides, perhaps a very subjective aesthetic pleasure and a warm and fuzzy feeling for the instigator, and some are actually dangerous to use despite their initial appeal, because information redundancy, when maintained by humans, is seldom redundant in the face of changes.

Ordinal Serialization

Serialization

Serialization is the process of turning an in-memory non-linear data structure into a sequence of bytes that can be used, at another place or another time, to construct the original in-memory data structure. It’s the equivalent of putting the data structure in a box before moving to a new house (or to keep it in the basement for later use).

Today, serialization is a solved problem. Most programming languages provide serialization as a standard library feature (PHP’s serialize, OCaml’s Marshal module) or as a common extension (C++’s boost::serialization). These packages solve countless problems encountered when serializing arbitrary data: handling collections, handling polymorphism, handling object graph joins or cycles, and even the low-level issues of binary serialization, such as endian-independent memory layouts. There is, as such, no reason to use your own serialization method without first trying out these methods.

Ordinal serialization

These methods, however, have the issue of being as general as possible. As such, they often generate serialized data that is too large when compared to the actual data being stored. This is of course perfectly normal: without prior knowledge of the data set, an algorithm cannot be optimized for either size or speed. For instance, if the programmer knows that the object graph is a tree (no joins or cycles), the serializer will still have to place additional data in the stream to tell the deserializer that no joins or cycles were encountered.

A such example of overhead applies to indexes. In general, indexes are numbers between zero and the size of a container, and they are used quite a fair lot in data structures. So, if the container has a size of 172, all indices fit in a single 8-bit byte, yet will be represented by most binary serialization systems as a four-byte or eight-byte value in memory, leaving it to a compression algorithm down the pipeline to compress the three unnecessary “zero” bytes away.

If ordinals are assumed to be close to zero with a higher probability, then a possible optimization is to pack as many ordinals in a single byte, then in the following byte, and so on. The memory representation thus uses, for each byte, 7 bits to represent the value and 1 bit to determine whether this is the last byte of the ordinal or if another byte exists. This method also has the advantage of eliminating any endianness issue, since it uses individual bytes.

The code

The piece of code below provides two functions for writing and reading an ordinal (represented as an unsigned number) from an iterator. The iterator’s value_type should be unsigned char (or be compatible with it). Possibilities would be an std::back_insert_iterator< std::vector<unsigned char> > or an std::ostream_iterator< unsigned char > over the appropriate output stream.

namespace ordinal
{
    template <typename It>
    void put(unsigned value, It &target)
    {
        while (value > 127)
        {
            *target++ = static_cast<unsigned char>(value % 128) + 128;
            value /= 128;
        } 

      *target++ = static_cast<unsigned char>(value);
    } 

    template <typename It>
    unsigned get(It &source)
    {
        unsigned char read;
        unsigned multiplier = 1;
        unsigned result = 0;
        while ((read = *source++) > 127)
        {
            result += (static_cast<unsigned>(read) - 128) * multiplier;
            multiplier *= 128;
        } 

        result += static_cast<unsigned>(read) * multiplier; 

        return result;
    }
}

This is a fairly common trick, encountered in countless file format specifications (take a peek at some of the binary formats for 3D models at wotsit and see how they represent endian-independent indices). The code above is hereby placed in the public domain, where allowed by law.