Lifetime follows scope

Problem Improving the performance of an object-oriented program that uniformly allocates its objects from the heap.

Context During design, when establishing object scope and lifetimes.

Forces In the procedural computational model, data lifetimes follow the lifetime of procedure activation records, which map closely to function scopes. Because functions are "inside" objects in object-oriented programs, the data (objects) tend to outlive the procedures. Yet many C++ programs exhibit a procedural flow at the use-case level that employs the services of lower-level objects like strings, lists, sets, and streams. This is particularly true for programs using C++ as a "better C," and is true in lesser degree for more advanced C++ programs.

Object-oriented programming also brings an additional level of scope not found in procedural programming: the class. The lifetime of many class objects follows the lifetimes of their enclosing objects. For example, the lifetime a string object may be tied to the lifetime of the FileNarne class that contains it; the lifetime of the string object is bounded by the lifetime of the enclosing FileName object. Of course, not all strings are enclosed in FileName objects.

A single, uniform memory management strategy makes code easy to understand. One could use operator new as the single, uniform mechanism to create all objects and operator delete to free them. However, these operators are often the performance "hot spots" of strongly object-oriented programs. And memory management leaks from new and delete are the single largest cause of testing bugs in sophisticated C++ programs.

Solution For those cases where the object lifetime follows the scope, declare the object as a proper member of the scope. Let the language invoke the constructors and destructors automatically.

Examples Not this:
    void foo() {
        SomeClass *x = new SomeClass;
        ....
        delete x: }
    
but this:
    
    void foo() {
        SomeCtass x;
        .... }
    
and not this:
    
    class Bar {
        SomeClass *x;
    public:
        Bar() : x(new SomeClass) { .... }
        ~Bar() { delete x; .... }
        .... };
    
but this:
    class Bar {
        SomeCtass x:
    public:
        Bar() : x() { .... )
        .... };
    
Resulting context There will be reduced memory fragmentation from new and delete, and the code will run faster because of reduced memory management overhead. This pattern removes one level of pointer overhead as well. The program is likely to have less garbage, because more objects will be properly cleaned up even in the face of exceptions or user negligence.

[Source: James Coplien, "After all, we can't ignore efficiency", C++ Report, May 96, p66]