Optimizing C++/Writing efficient code/Constructions and destructions

Construction and destruction of an object requires time, especially if the object owns other objects.

This section will provide guidelines for decreasing the number of object constructions and corresponding destructions.

Variable scope
Declare variables as late as possible.

To do so, the programmer must declare all variables in the most local scope. By doing so, the variable is neither constructed nor destructed if that scope is never reached. Postponing declaration as far as possible within a scope means that should there be an early exit before the declaration (using a   or   or   statement) the object associated to the variable is neither constructed nor destructed.

It is often the case that at the beginning of a routine no appropriate value is available with which to initialize a variable. The variable is therefore initialized with a default value and a later assignment sets the correct value when it becomes available. If, instead, the variable is defined only when an appropriate value is available, the object is initialized with this value and no subsequent assignment is necessary. This is advised by the guideline "Initializations" in this section.

Initializations
'''Use initializations instead of assignments. In particular, in constructors, use initialization lists.'''

For example, instead of writing:

write:

Even if a class instance (s in the first example above) is not explicitly initialized, it is nevertheless automatically initialized by the default constructor.

To call the default constructor followed by an assignment with a value may be less efficient than to call only a constructor with the same value.

Increment/decrement operators
Use prefix increment or decrement  operators instead of the corresponding postfix operators if the expression value is not used.

If the incremented object is a primitive type, there is no difference between prefix and postfix operators. However, if it is a composite object, the postfix operator causes the creation of a temporary object, while the prefix operator does not.

Because every object that is a primitive type may become a composite object in the future, it is better to use the prefix operator whenever possible, especially when writing generic (templatized) code that operates on iterators.

Use the postfix operator only when the variable is in a larger expression and must be incremented only after the expression is evaluated.

Assignment composite operators
Use the assignment composite operators (like in ) instead of simple operators combined with assignment operators (like in  ).

For example, instead of the following code:

write the following code:

Typically, a simple operator creates a temporary object. In the example, the operator  creates temporary strings whose creation and destruction require much time.

On the contrary, the equivalent code using the  operator does not create temporary objects.

Function argument passing
When you pass an object  of type   as argument to a function, use the following criterion:
 * If  is an input-only argument,
 * if  may be null,
 * pass it by pointer to constant ,
 * otherwise, if  is a fundamental type or an iterator or a function-object,
 * pass it by value or by constant value ,
 * otherwise,
 * pass it by reference to constant ,
 * otherwise, i.e. if  is an output-only or input/output argument,
 * if  may be null,
 * pass it by pointer to non-constant ,
 * otherwise,
 * pass it by reference to non-constant .

Pass by reference is more efficient than pass by pointer as it facilitates variable elimination by the compiler and because the callee need not check whether the reference is valid or null. However, where the argument can be missing, it is more efficient to pass a NULL pointer, than to pass a reference to a possibly dummy object and a boolean indicating whether the reference is valid.

For objects that may be contained in one or two registers, pass by value is more efficient than pass by reference (or equally efficient). This applies to tiny objects, such as the fundamental types, iterators and function-objects. For larger objects, pass by reference is more efficient than pass by value, as with the latter, the object must be copied onto the stack.

A composite object that is currently fast to copy might be passed efficiently by value. However, unless the object is an iterator or a function-object (which are assumed always to copy efficiently), this technique is risky. Future changes to the object might increase its size and make it more expensive to copy. For example, if an object of class  contains only two  s, it could be efficiently passed by value; but if in the future a third   is added, or if the two  s become two  s, it could become more efficient pass by reference.

declaration
Declare as  all constructors that receive only one argument, except for the copy constructors of concrete classes.

Non- constructors may be called automatically by the compiler when it performs an automatic (implicit) type conversion. The execution of such constructors may take much time.

If such conversion is made compulsorily explicit, and if a new class name is not specified in the code, the compiler could choose another overloaded function, avoiding to call the costly constructor, or it could generate an error, so forcing the programmer to choose another way to avoid the constructor call.

For copy constructors of concrete classes a distinction must be made to allow their pass by value. For abstract classes, even copy constructors may be declared, as, by definition, abstract classes cannot be instantiated and so objects of such type should never be passed by value.

Conversion operators
Declare conversion operators only to keep compatibility with an obsolete library (in C++11, declare them ).

Conversion operators allow implicit conversions and so incur in the same problem as implicit constructors described in the guideline " declaration" in this section.

If such conversions are needed, provide instead an equivalent member function, as it may only be called explicitly.

The only acceptable remaining usage for conversion operators is when a new library must coexist with an older similar library. In such a case, it may be convenient to have operators that automatically convert objects from the old library into the corresponding types of the new library and vice versa.

The Pimpl idiom
Use the Pimpl idiom only when you want to make the rest of the program independent from the implementation of a class.

The Pimpl idiom (meaning Pointer to implementation) consists of storing in an object only a pointer to a data structure containing all the useful information about the object.

The main advantage of the idiom is that it speeds up incremental compilation of code by making it less likely that a small change in the source code causes the need to recompile a large number of code lines.

This idiom also makes some operations more efficient, such as a  of two objects. In general, however, it slows down every access to the object data because of the added level of indirection and causes an additional memory allocation each time such an object is created or copied. It should not, therefore, be used for classes whose public member functions are called frequently.

Iterators and function objects
Ensure that custom iterators and function objects are tiny and do not allocate dynamic memory.

STL algorithms pass such objects by value. Therefore, if their copy is not extremely efficient, STL algorithms are slowed down.

If an iterator or function object for some reason needs an elaborate internal state, allocate it dynamically and use a shared pointer. For example, say you want to implement an STL-compliant 32-bit Random Number Generator on top of the Linux/OpenBSD  device:

In this case, the use of a pointer was actually necessary because the  class is non-copyable: its copy constructor is declared. This example uses the  smart pointer; for more speed, intrusive reference counting could be used.

Ottimizzare C++/Scrivere codice C++ efficiente/Costruzioni e distruzioni