Unit 3 · OOP Concepts

3.1.5Destructors and releasing resources

What a destructor is

A destructor is a method that runs when an object is destroyed, to release resources (files, network connections, memory).

Java
class Report implements AutoCloseable {
    Report() { System.out.println("Report opened"); }

    @Override
    public void close() { System.out.println("Report closed"); }
}

try (Report r = new Report()) {
    System.out.println("Working...");
}   // close() is called automatically here

Output: Report opened, Working..., Report closed.

For comparison, here is the same idea in C++. The destructor runs automatically, at a predictable moment, when the object goes out of scope:

C++
#include <iostream>
using namespace std;

class Report {
public:
    Report()  { cout << "Report opened" << endl; }
    ~Report() { cout << "Report closed" << endl; }   // destructor
};

int main() {
    Report r;                          // constructor runs
    cout << "Working..." << endl;
    return 0;
}                                      // r goes out of scope: destructor runs

Why releasing resources matters

Memory is not the only thing an object can hold. Objects often hold resources that belong to the operating system or to another program: an open file, a database connection, a network socket or a printer. There is only a limited number of these. If a program opens files and never closes them, it eventually cannot open any more. A database server may refuse new connections, and data written to a file may never actually be saved to disk.

The garbage collector frees memory, but you cannot know when it will run (see 3.2.2). Waiting for it to close a file is not good enough. So in Java you close resources yourself, at a moment you choose.

How try-with-resources works

Java
try (Report r = new Report()) {   // the resource is opened here
    r.write();
}                                  // r.close() is called here, automatically

Before Java 7, programmers had to call close() in a finally block. That approach still works, but it is longer and easy to get wrong.

C++ destructors and RAII

In C++, a destructor runs at an exact, predictable moment: when a local object goes out of scope at the closing }, or when delete is used on an object created with new. C++ programmers use this to tie a resource to an object's lifetime: the constructor opens the resource and the destructor closes it. This idea is called RAII (Resource Acquisition Is Initialisation). Java's try-with-resources gives the same safety in a different way.

LanguageMemory freed byResources released by
C++The programmer (delete) or automatically at the end of scopeThe destructor ~ClassName()
JavaThe garbage collectorclose(), usually through try-with-resources
PythonAutomatic (reference counting and a garbage collector)with statements and close()

Remember

  • Java has no destructors; the garbage collector frees memory at a time you cannot predict.
  • Release files, connections and other resources yourself, with close() or try-with-resources.
  • In C++, a destructor runs automatically when an object goes out of scope or is deleted.