Defer in C++

Our first program demonstrates the use of defer, which is used to ensure that a function call is performed later in a program’s execution, usually for purposes of cleanup. In C++, we can achieve similar functionality using RAII (Resource Acquisition Is Initialization) and smart pointers.

#include <iostream>
#include <fstream>
#include <memory>

// Custom deleter for our file handler
struct FileDeleter {
    void operator()(std::ofstream* file) {
        std::cout << "closing" << std::endl;
        if (file->is_open()) {
            file->close();
        }
        delete file;
    }
};

// Using a unique_ptr with custom deleter to mimic defer behavior
using FilePtr = std::unique_ptr<std::ofstream, FileDeleter>;

FilePtr createFile(const std::string& path) {
    std::cout << "creating" << std::endl;
    auto file = std::make_unique<std::ofstream>(path);
    if (!file->is_open()) {
        throw std::runtime_error("Unable to create file");
    }
    return FilePtr(file.release());
}

void writeFile(FilePtr& file) {
    std::cout << "writing" << std::endl;
    *file << "data" << std::endl;
}

int main() {
    try {
        auto f = createFile("/tmp/defer.txt");
        writeFile(f);
        // The file will be automatically closed when f goes out of scope
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

In this C++ version, we use a std::unique_ptr with a custom deleter to mimic the behavior of defer. The FileDeleter struct defines the cleanup action that will be performed when the unique_ptr is destroyed.

The createFile function returns a FilePtr, which is a unique_ptr to an ofstream with our custom deleter. This ensures that the file will be properly closed when it goes out of scope, similar to how defer works in the original example.

The writeFile function takes a reference to our FilePtr and writes to the file.

In the main function, we create the file and write to it. The file will be automatically closed when f goes out of scope at the end of the try block, or if an exception is thrown.

To run the program:

$ g++ -std=c++14 defer_example.cpp -o defer_example
$ ./defer_example
creating
writing
closing

This example demonstrates how to use RAII principles in C++ to achieve similar functionality to defer in other languages. The file is automatically closed at the end of the program’s execution, ensuring proper resource management.