What is std::promise in C++?

C++’s std:promise is a powerful tool for managing asynchronous data transfers between threads. It is defined in the <future> header and works in tandem with std::future to synchronize thread operations. Let’s dive into its mechanics, usage, and some practical examples.

The std::promise forms

The std::promise class template is available in three forms:

  • Base template: It’s the generic form used for most data types. It can be written as template< class R > class promise;.

  • Nonvoid specialization: It’s used when passing nonvoid types (like objects) between threads. It can be written as template< class R > class promise<R&>;.

  • Void specialization: It signals state changes or events without passing data. It can be written as template<> class promise<void>;.

A std::promise object is tied to a shared state, representing either a value, an exception, or a state of readiness. Here are the key operations a std::promise can perform the following:

  • Make ready: It stores a result or exception in the shared state and unblocks any waiting threads.

  • Release: It releases the reference to the shared state, potentially destroying it if it’s the last reference.

  • Abandon: It stores a std::future_error exception and readies the state before releasing it.

Code examples

Now that we have a foundational understanding of std::promise and its various forms, let’s delve into some practical applications. These code examples will illustrate how std::promise can be effectively utilized in different scenarios, providing a clearer perspective on its functionality and versatility.

Example 1: Simple integer transfer

This example demonstrates how to transfer a simple integer value from a secondary thread back to the main thread using std::promise and std::future. The secondary thread performs some work and sets the promise’s value, which is then retrieved by the main thread through the future. This pattern is crucial for tasks where the main thread needs to wait for a result calculated by a secondary thread.

#include <iostream>
#include <future>
#include <thread>
// This function will be executed in a separate thread
void threadFunction(std::promise<int>&& promiseObj) {
// Simulate some work in the thread
// ...
// Set the result of the promise to 42
promiseObj.set_value(42);
}
int main() {
// Create a std::promise object that can hold an integer
std::promise<int> promise;
// Obtain a std::future object from the promise
// The future object will eventually hold the result that the promise sets
std::future<int> future = promise.get_future();
// Start a new thread and pass the promise to it using std::move
// std::move is used because promises cannot be copied, only moved
std::thread th(threadFunction, std::move(promise));
// Wait for the result from the future object
// This will block until the thread sets a value in the promise
int result = future.get();
// Output the result obtained from the thread
std::cout << "Result from Thread: " << result << std::endl;
// Wait for the thread to complete its execution
// This is necessary to ensure that the program does not exit before the thread finishes
th.join();
return 0;
}
Simple integer transfer

In this example, we use std::promise to pass an integer from a secondary thread back to the main thread. The secondary thread sets the value of the promise, which the main thread retrieves using a future.

Example 2: Signaling a state change (void specialization)

This example uses std::promise<void> to signal the completion of a task in a secondary thread without transferring any specific data. It illustrates how to use the void specialization of std::promise to synchronize operations between threads, especially useful in scenarios where the main thread needs to wait for a signal from secondary threads indicating that their tasks are complete.

#include <iostream>
#include <future>
#include <thread>
// Function to be executed in the secondary thread
void threadFunction(std::promise<void>&& promiseObj) {
// Perform some actions in the thread
// ...
// Signal the completion of the task
promiseObj.set_value();
}
int main() {
// Create a std::promise object that doesn't hold any specific data
std::promise<void> promise;
// Obtain a std::future object from the promise
// This future will be used to wait for a signal from the secondary thread
std::future<void> future = promise.get_future();
// Start a new thread, passing the promise to it
// The std::move is necessary because the promise cannot be copied, only moved
std::thread th(threadFunction, std::move(promise));
// Wait for the secondary thread to signal completion
// The main thread will block here until the promise is fulfilled
future.wait();
// After the signal is received, print a confirmation message
std::cout << "Thread completed its action" << std::endl;
// Wait for the secondary thread to finish its execution
// This ensures the program doesn't exit prematurely
th.join();
return 0;
}
Signaling a state change (void specialization)

Here, std::promise<void> is used to signal the completion of an action in a thread without transferring any data.

Example 3: Handling exceptions

In this final example, a secondary thread throws an exception that is caught and forwarded to the main thread through the promise-future mechanism. This demonstrates how std::promise can be used to propagate exceptions from a secondary thread to the main thread, enabling robust error handling in multithreaded applications.

#include <iostream>
#include <future>
#include <thread>
#include <exception>
// Function to be executed in a separate thread
void threadFunction(std::promise<int>&& promiseObj) {
try {
// Simulating some work in the thread that might throw an exception
throw std::runtime_error("Exception from thread");
} catch(...) {
// If an exception is caught, pass it to the main thread
// std::current_exception captures the current exception in a std::exception_ptr
promiseObj.set_exception(std::current_exception());
}
}
int main() {
// Create a std::promise object that will hold an integer
std::promise<int> promise;
// Get a std::future object from the promise
// This future will be used to retrieve the result or exception set by the secondary thread
std::future<int> future = promise.get_future();
// Start a new thread, passing the promise to it
std::thread th(threadFunction, std::move(promise));
try {
// Attempt to get the result from the future
// This call will block until the secondary thread sets a value or an exception
int result = future.get();
// (Optional) Process the result here
} catch(const std::exception& e) {
// If an exception was thrown in the secondary thread, catch it here
std::cout << "Main thread caught exception: " << e.what() << std::endl;
}
// Ensure that the thread completes its execution
th.join();
return 0;
}
Handling exceptions

In this final example, the thread throws an exception, which is caught and passed back to the main thread through the promise-future mechanism.

Conclusion

std::promise in C++ offers a robust way to manage asynchronous operations between threads, either by transferring data, signaling events, or propagating exceptions. Understanding and using this tool effectively can greatly enhance the robustness and efficiency of multithreaded applications in C++.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved