What is std::future in C++?

In C++ programming, the need for efficient handling of asynchronous operations has become increasingly prevalent. The std::future class template emerges as a powerful mechanism, providing a structured way to access the results of asynchronous tasks. We will explore the capabilities of std::future and how it can enhance your C++ programming experience.

Why use std::future?

std::future is a template class in the <future> header file. It provides a mechanism to access the result of asynchronous operations, which might not be complete when the std::future object is queried.

At its core, std::future is a channel between asynchronous operations and their creators. Whether we are using std::async, std::packaged_task, or std::promise, std::future acts as the bridge, enabling communication between the producer and consumer of asynchronous results.

Steps to use std::future

  1. Creation of asynchronous operations:

    1. We can create asynchronous operations using std::async, std::packaged_task, or std::promise.

    2. For instance, std::packaged_task<int()> and std::promise<int> encapsulate callable objects, while std::async provides a convenient way to launch asynchronous tasks.

  2. Linking futures to asynchronous tasks:

    1. After creating an asynchronous operation, obtain an std::future object to access its results.

    2. Using std::packaged_task::get_future(), std::async's return value, or std::promise::get_future(), establish a link between the asynchronous operation and the std::future.

  3. Waiting and extracting results:

    1. Employ the various methods provided by std::future to interact with asynchronous tasks, such as wait(), wait_for(), and wait_until().

  4. Result retrieval:

    1. Once the asynchronous task is finished, we can obtain its result using the get() method of std::future.

Code example

The example below demonstrates how to use std::future with std::async to run a function asynchronously and retrieve its result.

#include <future>
#include <iostream>
#include <thread>
int main() {
// Example using std::packaged_task
std::packaged_task<int()> task([]{ return 7; });
std::future<int> f1 = task.get_future();
std::thread t(std::move(task));
// Example using std::async
std::future<int> f2 = std::async(std::launch::async, []{ return 8; });
// Example using std::promise
std::promise<int> p;
std::future<int> f3 = p.get_future();
std::thread([&p]{ p.set_value_at_thread_exit(9); }).detach();
// Wait for completion and retrieve results
f1.wait();
f2.wait();
f3.wait();
std::cout << "Results: " << f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';
t.join();
return 0;
}
Example code of using std::future

Code explanation

Here is a line-by-line explanation of the code above:

  • Lines 1–3: Including the required libraries.

  • Line 7: A std::packaged_task<int()> is created, encapsulating a callable object (lambda function) that returns an integer.

  • Line 8: task.get_future() obtains a std::future<int> associated with the packaged task.

  • Line 9: std::thread t(std::move(task)); creates a new thread, t, and moves the ownership of the packaged task (task) to this thread.

  • Line 12: An asynchronous task is launched using std::async. It returns a std::future<int> representing the asynchronous operation.

  • Line 15: A std::promise<int> is created, providing a shared state for communication.

  • Line 16: p.get_future() retrieves a std::future<int> linked to the promise.

  • Line 17: A thread is detached, setting the promise's value at thread exit: p.set_value_at_thread_exit(9).

  • Lines 20–22: f1.wait(), f2.wait(), and f3.wait() are used to block until the associated asynchronous tasks are complete.

  • Line 23: f1.get(), f2.get(), and f3.get() are called to retrieve the results of the asynchronous operations. These calls may be blocked until the asynchronous tasks have provided a value. The final results are printed, showcasing the values obtained from the three asynchronous tasks.

  • Line 24: t.join() ensures the main thread waits for the detached thread (t) to complete before exiting.

Note: The output shows that the program waits for all the future objects (f1, f2, and f3) to be ready using their wait() method. Once they are ready, it retrieves and prints the results using get().

Conclusion

In conclusion, std::future in C++ is an essential tool for facilitating asynchronous programming, allowing developers to manage and retrieve results from parallel tasks efficiently. It simplifies handling concurrent operations and error management, making it easier to build responsive and robust applications. Understanding std::future is crucial for leveraging the full potential of modern C++ in developing high-performance, concurrent applications.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved