Skip to content
C++ Basics: Retry Initialization after std::call_once Throws

C++ Basics: Retry Initialization after std::call_once Throws

November 3, 2026

Distinguish an initialization attempt from the one successful execution recorded by a once_flag.

Prepare a scratch directory

Tested on Linux x86_64 with GCC 14.2.0. Install a C++20-capable GCC compiler and its standard-library development files, with g++ on PATH. You also need Bash, a text editor, and mktemp, rm, and rmdir. No third-party library is required.

Keep the same terminal open. Stop if setup fails before saving the source:

start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1

Run the example

Save this as call-once-retry-demo.cpp:

#include <iostream>
#include <mutex>
#include <stdexcept>

int main()
{
    std::once_flag initialization_flag;
    int attempts = 0;
    int configuration = 0;
    const auto initialize = [&] {
        ++attempts;
        if (attempts == 1) {
            throw std::runtime_error("temporary initialization failure");
        }
        configuration = 42;
    };

    try {
        std::call_once(initialization_flag, initialize);
    } catch (const std::runtime_error& error) {
        std::cout << "First attempt: " << error.what() << '\n';
    }
    std::call_once(initialization_flag, initialize);
    std::call_once(initialization_flag, initialize);
    std::cout << "Attempts: " << attempts << '\n';
    std::cout << "Configuration: " << configuration << '\n';
}

Compile and run it. The second command runs only after compilation succeeds:

g++ -std=c++20 -Wall -Wextra -Werror -pedantic -pthread call-once-retry-demo.cpp -o call-once-retry-demo &&
./call-once-retry-demo

Observed output:

First attempt: temporary initialization failure
Attempts: 2
Configuration: 42

Read the result

The first call propagates the exception and does not mark initialization successful. The second call executes initialize again and returns normally. The third call skips it. Three calls therefore produce two attempts and one successful initialization. The calls are sequential here to keep the retry sequence easy to inspect.

Apply it carefully

Concurrent callers using the same flag are coordinated by call_once, but the flag does not roll back side effects from a failed attempt. Make retries safe and catch failures where the application can recover. There is no reset operation on once_flag. If you need replaceable configuration, use a different lifetime and synchronization design.

The C++ working draft documents the relevant rules. This example uses C++20 facilities; the current draft also contains newer additions.

Clean up

Remove only the source and executable created here, then remove the empty practice directory:

rm -- call-once-retry-demo.cpp call-once-retry-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directory

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on