Concepts / Abstraction and Resource Management in C++

Abstraction and Resource Management in C++

A resource handle is an object that holds a resource on behalf of the code using it.

  • Programming

Types for the Ideas in a Program

C++ programs work with types. Some types, such as built-in number types, come with the language. C++ also lets programmers define named types of their own, called user-defined types. These let a program represent an idea from its problem domain, such as a bank account, a shape, or a sensor reading, as a type.

Type familyWhere it comes fromWhat it lets a program represent
Built-in typeProvided by C++A built-in value such as a number
User-defined typeDefined by the programmerA named idea from the program's problem domain

The distinction is about where the type comes from: C++ provides built-in types, while the programmer defines user-defined types.

Concrete classes, abstract classes, and class hierarchies are three useful ways to think about user-defined types. The first question to ask about a class is whether you can create an object from it. That question separates concrete classes from abstract classes; inheritance explains how related classes can share a structure.

Whether a Class Can Become an Object

A concrete class is not abstract: you can create an object from it. The object is an instance of that type and can hold data and respond to operations defined by the class. An abstract class cannot be instantiated on its own. Its purpose is to provide a common base for classes that derive from it; objects are created from those derived classes instead.

Abstract classCannot be instantiated onits ownConcrete derivedclassCan be instantiatedObjectbase forcreates
Which class can be instantiated, and how does an abstract class relate to the classes that can be instantiated?
Worked example

Classifying a shape hierarchy

A program has a general Shape class and more specific Circle, Square, and Triangle classes that inherit from it. What can you conclude about their relationships, and what test would decide whether each class is concrete or abstract?

  1. 1
    Read the inheritance

    Shape is the general type, and Circle, Square, and Triangle are specific types that inherit from it.

  2. 2
    Apply the instantiation test

    For each class, ask whether an object can be created from that class itself. If yes, it is concrete; if no, it is abstract.

Result

The inheritance relationships identify a hierarchy, but the names alone do not establish which classes are abstract or concrete. Use the object-creation test for each class.

ShapeGeneral classCircleSpecific classSquareSpecific classTriangleSpecific classbase ofbase ofbase of
How does inheritance arrange a general class and more specific classes?
Key point

Do not classify a class just from its name or its place in a hierarchy. The decisive test is whether an object can be created from it.

The Constructor-to-Destructor Responsibility

A class may need a limited resource, such as memory, a file, or a lock, to do its job. If its constructor acquires that resource, the class has taken on a responsibility: the resource must later be released. The destructor is the natural place for that release, because it marks the end of the object's lifetime.

ConstructorResource acquiredObject uses resourceDestructorResource releasedacquireswhile the object livesobject lifetime endsreleases
In what order does construction, resource acquisition, and destruction happen, and when is the resource released?

The sequence ties the resource's start and end to the object's start and end. Acquisition happens during construction; release belongs in the destructor. With that responsibility attached to the object's lifetime, the program does not depend on a separate hand-written release step being reached. If the destructor does not release a resource acquired by the constructor, the resource can remain held after the object that needed it is gone.

Worked example

Checking a resource-owning class

Suppose a class acquires an array on the heap in its constructor. What responsibility follows from that acquisition?

  1. 1
    Find the acquisition

    The constructor takes control of the array resource.

  2. 2
    Find the matching release

    The class needs a destructor that releases the resource when the object is destroyed.

Result

The class should pair its constructor's acquisition with release in its destructor.

RAII and Resource Handles

Definition

RAII stands for Resource Acquisition Is Initialization. It is the pattern in which a resource is acquired during an object's initialization, so the object's lifetime controls the resource's lifetime.

A resource handle is an object that holds a resource on behalf of the code using it. The handle acquires the resource when it is created and releases it when it is destroyed. Calling code works through the handle rather than taking on the release bookkeeping itself. Requests and values pass from the caller through the handle to the resource; results travel back through the handle to the caller.

Naked newResource handleHolds resource for callerResourceMust be releasedResourceMatching deleteProgrammer must ensure ithappensHandle destructionReleases resourceacquiresrequiresholdsreleased on
What responsibility remains with the programmer when using naked new and delete, compared with letting a resource handle manage acquisition and release?

The key difference is who carries the release responsibility. With naked operations, the programmer must arrange the matching release. With a resource handle, the handle's destruction releases the resource, and the caller uses the resource through the handle. This describes the management pattern without requiring a particular handle type.

Creating a Container with Initial Values

A container class holds a collection of elements. An initializer-list constructor accepts values written in braces, allowing a container to be created already filled with those values. The elements come from the braced list, so the object is populated at creation time. This makes small collections easier to create and read.

Braced valuesValues supplied at creationInitializer-listconstructorAccepts the listContainer elementsObject starts populatedprovided toinitializes
How do values written in braces become the initial contents of a container?
Worked example

Reasoning about a container initializer

A container class is given an initializer-list constructor, and a caller supplies values in braces when creating the container. What should you expect about the new object?

  1. 1
    Identify the constructor input

    The braced list supplies values to the initializer-list constructor.

  2. 2
    Follow the values into the object

    The container's elements come from that list, so it is populated as it is created.

Result

The container begins with the supplied values as its elements.

Mistakes in Classification and Resource Management

  • Common mistake

    Calling a class concrete because it is a specific-sounding type.

    What it looks like

    Assuming that Circle must be concrete just because it names a specific kind of shape.

    Why it fails

    A class's name does not establish whether objects can be created from it.

    Do this instead

    Check whether an object can be created from the class itself. If yes, it is concrete; if no, it is abstract.

  • Common mistake

    Treating an abstract class as though it were an object type that can be instantiated directly.

    Why it fails

    An abstract class cannot be instantiated on its own; it serves as a base for derived classes.

    Do this instead

    Create objects from concrete classes that derive from the abstract class.

  • Common mistake

    Acquiring a resource in a constructor without providing for its release.

    Why it fails

    The resource can remain held after the object that needed it is gone.

    Do this instead

    Give the class a destructor that releases the resource acquired by the constructor.

  • Common mistake

    Writing naked new and assuming a matching delete will take care of itself.

    Why it fails

    The programmer must ensure that every required matching delete happens on every path.

    Do this instead

    Prefer a resource handle using RAII so release is tied to the handle's destruction.

  • Common mistake

    Making a container that accepts only later additions when it should also be convenient to create with initial values.

    Why it fails

    Without an initializer-list constructor, the container cannot use the described braced-list creation interface.

    Do this instead

    Provide an initializer-list constructor so the container can start with the supplied elements.

Check Your Understanding

MEDIUM

A class named Device acquires a resource in its constructor. The class is intended to be a complete type from which the program creates objects. Explain how you would classify it, what its destructor must do, and how a resource handle using RAII could change who is responsible for release. Then describe what an initializer-list constructor would let a container user provide at creation time.

Hints
  • Use the object-creation test to distinguish concrete from abstract.
  • Connect constructor acquisition to destructor release.
  • A resource handle acquires and releases on behalf of calling code.
  • An initializer-list constructor accepts values written in braces.

Key Takeaways

  • Built-in types come with C++; user-defined types let programmers represent named ideas from a problem domain.
  • A concrete class can be instantiated. An abstract class cannot be instantiated on its own and is intended to serve as a base for derived classes.
  • A class hierarchy organizes related types through inheritance, from general classes toward more specific ones.
  • When a constructor acquires a resource, the class needs a destructor to release it. RAII and resource handles tie that release to object lifetime.
  • Naked new and delete leave matching-release work with the programmer; an initializer-list constructor lets a container start with supplied braced values.

Related concepts

More concepts starting with A