Search code examples
c++lazy-initializationraii

How to implement RAII + lazy initialization?


Is it possible to implement in C++ a design that is both - RAII, to ensure the resource is safely released, and - lazy initialzation, that the resource is acquired only when it's really used.

My idea is that just implement as a lazy initialization, while in the real resource acquisition, use RAII.

How's the industry practice?


Solution

  • Yes, it's possible. Just use std::optional (C++17 or from Boost) or unique_ptr/shared_ptr.

    (opinion) optional has a great advantage in the readability - you can't be any clearer that this value may not be initialized.

    To show that resources are released correctly: first let's start with eager initialization (live):

    ofstream file("test.txt");
    file << "no flush\n";
    
    ifstream inFile("test.txt");
    string line;
    getline(inFile, line);
    cout << line << endl;
    

    This, doesn't print anything for me¹. Let's move writing to a separate scope (live):

    {
        ofstream file("test.txt");
        file << "no flush\n";
    }
    
    ifstream inFile("test.txt");
    string line;
    getline(inFile, line);
    cout << line << endl;
    

    This should print no flush, because ofstream is guaranteed to close() the file upon destruction. (unless something else accessed test.txt at the same time)

    And now with Boost.Optional and lazy init (live):

    {
        boost::optional<std::ofstream> file;
    
        file = ofstream("test.txt");
        file.get() << "no flush\n";
    }
    
    ifstream inFile("test.txt");
    string line;
    getline(inFile, line);
    cout << line << endl;
    

    Resources are released at the same time as they were with regular ofstream.

    ¹ file access isn't guaranteed to be buffered, but it makes for a good example, also available on online compilers.