如何为std::future赋予共享状态?相关核心特性解析
Great question! As you already noted, a default-constructed std::future doesn't point to any shared state, and most of its constructors won't create one for you. Here are the three core ways to give a std::future a valid shared state, along with practical examples:
1. Use std::async
This is the most straightforward approach for getting a std::future tied to an asynchronous task. The std::async function launches a task (either async or sync, based on the launch policy you specify) and returns a std::future linked directly to the task's shared state.
Example code:
#include <future> #include <iostream> int main() { // Launch an async task that returns a value auto fut = std::async(std::launch::async, []() { return 42; }); // Verify the future has a valid shared state if (fut.valid()) { std::cout << "Task result: " << fut.get() << std::endl; // Outputs 42 } return 0; }
Right after calling std::async, fut.valid() will return true, so you can safely use methods like get() or wait() without undefined behavior.
2. Pair with std::promise
std::promise and std::future are designed to work in tandem: the promise is used to set a value (or exception), and the future retrieves it. You get a valid std::future by calling std::promise::get_future(), which binds both objects to the same shared state.
Example code:
#include <future> #include <thread> #include <iostream> int main() { std::promise<int> prom; std::future<int> fut = prom.get_future(); // fut now has a shared state // Spawn a thread to set the promise's value std::thread t([&prom]() { prom.set_value(100); }); if (fut.valid()) { std::cout << "Promise result: " << fut.get() << std::endl; // Outputs 100 } t.join(); return 0; }
Note: You can only call get_future() once per promise—doing it a second time will throw a std::future_error.
3. Use std::packaged_task
std::packaged_task wraps a callable object (like a function or lambda) and lets you retrieve a std::future linked to its return value. This gives you more control over task execution than std::async, since you decide when and where to run the task.
Example code:
#include <future> #include <thread> #include <iostream> int compute_value() { return 200; } int main() { std::packaged_task<int()> task(compute_value); // Wrap the compute function std::future<int> fut = task.get_future(); // Get the linked future // Run the task in a separate thread std::thread t(std::move(task)); if (fut.valid()) { std::cout << "Packaged task result: " << fut.get() << std::endl; // Outputs 200 } t.join(); return 0; }
After calling get_future() on the packaged task, the future has a valid shared state. You need to move the task to a thread (or execute it directly) to populate that state.
Bonus: Transfer via Move Semantics
While this isn't "assigning" a new shared state, remember you can transfer an existing shared state from one std::future to another using move construction:
std::future<int> fut1 = std::async(std::launch::async, [](){ return 50; }); std::future<int> fut2 = std::move(fut1); // fut2 now owns the shared state // fut1.valid() is now false, fut2.valid() is true
内容的提问来源于stack exchange,提问作者Raedwald

