Future and Promises in Modern C++
A Complete Beginner's Guide to Asynchronous Programming

Introduction
Imagine you're downloading a large file while editing a document. Your computer does not freeze waiting for the download to complete. It performs multiple tasks simultaneously.
As multi-core CPUs became common, C++ needed a standard mechanism for asynchronous programming and thread communication. C++11 introduced std::future and std::promise to solve this problem.
When Were Future and Promise Added?
Future and Promise were introduced in C++11.
#include <future>
The library introduced:
std::futurestd::promisestd::asyncstd::packaged_task
Why Were Future and Promise Needed?
Before C++11, developers relied on:
Shared variables
Mutexes
Condition variables
Polling loops
Callback functions
Example:
int result;
bool ready = false;
Problems:
Race conditions
Deadlocks
Busy waiting
Difficult debugging
Complex synchronization logic
Future and Promise provide a clean abstraction that handles synchronization safely.
Real-Life Analogy
Food Delivery Example:
Restaurant prepares food โ
std::promiseCustomer receives tracking token โ
std::future
The promise produces the result. The future receives the result later.
What is std::future?
A future represents a value that will become available later.
std::future<int>
Meaning:
I don't have the value yet, but I will receive it in the future.
What is std::promise?
A promise allows one thread to store a value which another thread retrieves later.
std::promise<int> promise;
Internal Working - Shared State
Future and Promise communicate through a hidden Shared State.
Producer Thread
|
std::promise
|
Shared State
|
std::future
|
Consumer Thread
Promise writes data. Future reads data.
Future Lifecycle
Create Promise
โ
Create Future
โ
Future Waiting
โ
Promise set_value()
โ
Future Ready
โ
future.get()
โ
State Consumed
Basic Example
#include <future>
#include <thread>
#include <iostream>
void worker(std::promise<int> promise)
{
std::this_thread::sleep_for(std::chrono::seconds(2));
promise.set_value(42);
}
int main()
{
std::promise<int> promise;
auto future = promise.get_future();
std::thread t(worker, std::move(promise));
std::cout << "Waiting...
";
int result = future.get();
std::cout << result << std::endl;
t.join();
}
Valid and Invalid Futures
After calling:
future.get();
The future becomes invalid.
if(future.valid())
{
auto value = future.get();
}
Exception Propagation
One major advantage is safe exception transfer across threads.
try
{
throw std::runtime_error("Database Error");
}
catch(...)
{
promise.set_exception(std::current_exception());
}
Consumer:
try
{
future.get();
}
catch(const std::exception& e)
{
std::cout << e.what();
}
Waiting APIs
wait()
future.wait();
wait_for()
future.wait_for(std::chrono::seconds(2));
wait_until()
future.wait_until(deadline);
Using std::async
int calculate()
{
return 10 * 20;
}
auto future = std::async(
std::launch::async,
calculate);
std::cout << future.get();
Output:
200
Async Launch Policies
std::launch::async
Creates a new thread.
std::async(std::launch::async, task);
std::launch::deferred
Executes only when get() is called.
std::async(std::launch::deferred, task);
Shared Future
Normal future supports one consumer.
std::future<int>
For multiple consumers:
std::shared_future<int>
Example:
auto sf = promise.get_future().share();
Multiple threads may call:
sf.get();
Packaged Task
std::packaged_task<int()> task(function);
Useful in:
Thread pools
Schedulers
Task queues
Future vs Promise vs Async
Promise
Produces value.
promise.set_value(100);
Future
Receives value.
future.get();
Async
Creates Promise and Future internally.
auto future = std::async(task);
Practical Industry Use Cases
Automotive ADAS
Camera processing
Radar processing
LiDAR processing
Sensor fusion
Example:
cameraFuture.get();
radarFuture.get();
lidarFuture.get();
performSensorFusion();
Cloud Services
OTA updates
Backend communication
Vehicle configuration downloads
Database Queries
Execute long-running queries asynchronously.
Image Processing
Pipeline stage synchronization.
GUI Applications
Keep UI responsive while background work continues.
Thread Pool Architecture
Task
|
packaged_task
|
Thread Pool
|
future
|
Consumer
Common in:
Trading systems
Backend servers
Game engines
ADAS middleware
Coroutines vs Future
Future and Promise:
C++11
Coroutines:
C++20
Future style:
auto value = future.get();
Coroutine style:
auto value = co_await task();
Common Mistakes
Calling get() Twice
future.get();
future.get();
Forgetting std::move
std::move(promise)
Never Calling set_value()
The waiting thread may block forever.
Performance Considerations
Good For:
One-time result transfer
Task synchronization
Exception propagation
Async operations
Not Good For:
High-frequency messaging
Real-time streaming
Massive message queues
Interview Questions
Difference between Future and Promise?
Promise produces data. Future consumes data.
Can Future be copied?
No, it is move-only.
Can one Promise create multiple Futures?
No.
Difference between Future and Shared Future?
Future supports one consumer. Shared Future supports multiple consumers.
What happens if Promise is destroyed before set_value()?
Future receives std::future_error.
Difference between get() and wait()?
get() waits and returns value
wait() only waits
Evolution of Modern C++
C++11 : Future, Promise, Async
C++14 : Async improvements
C++17 : Parallel algorithms
C++20 : Coroutines
C++23 : Concurrency improvements
Key Takeaways
Introduced in C++11
Found in <future> Simplifies thread synchronization
Eliminates busy polling
Supports exception propagation
Makes asynchronous programming easier
Widely used in automotive, embedded, backend and cloud systems Foundation for modern concurrency in C++
Conclusion
Future and Promise transformed C++ concurrency by providing a clean, safe, and standardized mechanism for asynchronous communication between threads. They hide much of the complexity of mutexes and condition variables while making code easier to write, debug, and maintain.
Whether you are building ADAS software, embedded systems, backend services, cloud platforms, or high-performance applications, understanding Future and Promise is essential for becoming a strong Modern C++ developer.
About the author
- Satish Waghole Expert Developer | Automotive Software Architect | Tech Enthusiast
Comments
Join the discussionNo comments yet. Be the first to comment.



