More C++ Idioms/Temporary Base Class

= Temporary Base Class =

Intent
Reduce the cost of creating temporary objects.

Motivation
Temporary objects are often created during execution of a C++ program. Result of C++ operators (unary, binary, logical, etc.) and return-by-value functions always give rise to temporary objects. For built-in types, the cost of creating temporaries is minimal because compilers often use CPU registers to manipulate them. However, creation of temporary objects can be quite expensive for user-defined classes that allocate memory in the constructor and may require expensive copy operations in the copy-constructor. Temporaries are often wasteful because their lifespan is usually very short and they exist only to be assigned to a named object (lvalue). Even though their lifespan is short, the C++ language rules require the compilers to create and destroy temporaries to maintain correctness of the program. (In reality, RVO and NRVO optimizations are allowed to eliminate some temporaries). The cost of creating and destroying temporaries can adversely affect the performance of programs that use heavy objects.

Consider, for instance, a  class that uses heap memory to store an array of integers. This class uses the usual RAII idiom to manage the resources: allocation in the constructor and de-allocation in the destructor. The copy constructor and the copy-assignment operator take care of maintaining exclusive ownership of the allocated memory.

Using objects of this class in expression such as below have several performance issues.

Temporary  objects are created as a result of every summation and they are destroyed immediately. For every pair of parenthesis in, a temporary object is needed. Creation and destruction of each temporary requires memory allocation and de-allocation, which is quite wasteful.

Temporary Base Class idiom is a way of reducing the overhead of temporaries in arithmetic expression such as the above. However, this idiom has major drawbacks as described towards the end.

Solution and Sample Code
Temporary Base Class idiom (TBCI) does not change the fact that temporary objects are created but it reduces (substantially) the cost of creating them. This is achieved by recognizing the places where temporaries are created and by using a type that is lightweight to create and destroy. Unlike C++11, C++03 does not have a language supported way of distinguishing temporary objects (rvalues) from named objects (lvalues). Const reference is the only way available in C++03 for binding a temporary object to a reference.

In TBCI idiom, each class for heavy objects is represented by two classes. One class, D (for derived), is meant to represent the named objects whereas another class, B (for base), is used to represent temporary objects. Users are expected to use only D class in variable/function declaration because objects of type D behave just like regular objects. For instance, deep copies are performed when copying D objects.

The B class is used for intermediate temporary objects created in arithmetic expressions. Creation and destruction of B type objects is transparent to the user provided all the results computed by D objects are assigned to another D object. The key difference between B and D classes is the copying behavior. Whenever a B or D object is created from a D object, a deep copy (i.e., new memory allocation and copying data) is performed. On the other hand, whenever a B or D object is created from a B object, a shallow copy (i.e., just copy pointers) is performed. These rules are also applicable to the assignment operators with an exception that existing memory may have to be deleted in the left hand side object (e.g, an assignment from a B to B or D). Moreover, unlike D objects, B objects do not have exclusive ownership of the data and therefore do not destroy it when a destructor is called.

Interfaces of B and D classes are designed carefully to fully support conversion from one another with respect to the rules of memory management given above. The following example is a TBCI version of the  class shown above. The  class is the main class whereas   class is meant to represent temporary matrices.

The interfaces of the above two classes reveal several things. Not only the classes have doubled, number of member function have also (nearly) doubled. In particular, copy-constructor, copy-assignment operator, overloaded  are declared for both   and. This is necessary to ensure that in all possible cases where  and   object come together, the behavior is well-defined.

The only way  objects are created are through the overloaded   in the   class. Whenever two  classes are added, the result is returned as a   object. The result of any subsequent additions of  objects are stored in the same   object that is a result of the first addition. This eliminates the need to allocate and de-allocate memory for temporary matrices. For instance, TBCI achieves efficiency by executing addition of 4 matrices in the following way.

New memory is allocated only when the  object is created the first time. The results of additions are stored in the temporary  object shown as. Finally, the result must be assigned to a  object to ensure that memory resources do not leak.

Note that other combinations of the arithmetic operations are also possible. In particular, when other higher precedence operators, such as binary multiplication and division are used, objects may be created in different order. For the sake of simplicity, only binary addition is shown in the examples and parentheses are used to enforce precedence. For instance, consider the following order of execution.

To obtain the above behavior, both the classes ( and  ) are implemented in an idiomatic way as shown below.

Some highlights of the above code are given here. objects are created only as a result of  additions. Addition of two  objects results in a freshly allocated   object. On the other hand, when any one of the objects being added are of  type, the result is stored in the memory referenced by the temporary.

constructor allocates memory but destroys it only when  is true. destructor responsible for freeing memory. Unlike copy-constructor of,   copy-constructor does a shallow copy. However, as mentioned before, construction of  from   does a deep copy with its exclusive memory.

is a key function in this idiom. Note that the result of the addition is stored in the temporary object itself thereby avoiding another allocation. The  that takes a   object as a parameter is interesting because it accepts   object by-value. This is necessary because an addition of two temporary objects should result into only one temporary object and the other one must be destroyed. objects do manage their memory, therefore, one of the objects is explicitly destroyed using. This would not have been possible if right-hand-side  is bound to a const-reference.

The  class is implemented in terms of. Construction of  from another   does an allocation and copy. On the other hand, construction of  from a   simply copies the pointers because   does not delete data. The same rules are applicable to the assignment operators of the  class. Finally,  destructor simply changes the   flag to   resulting into deleting the memory. To handle some rarely occurring cases correctly, assignments to a  object are also handled. An assignment from a  is simply a copy operation whereas an assignment from a   class requires destroying one of them and doing a shallow copy of the pointers.

Caveats

This idiom has some serious drawbacks.
 * The result of computation must be assigned to a derived class object ( object). Otherwise there is definite resource leak in the program. Such a convention is usually very hard to maintain.
 * As a consequence, this idiom is not even basic exception safe. If any intermediate memory allocation operation throws an exception, it is very likely that there would be a resource leak.

Known Uses
The TBCI Library

Related Idioms

 * Move Constructor
 * Computational Constructor
 * Resource Acquisition Is Initialization