{"id":112769,"date":"2026-10-13T07:00:00","date_gmt":"2026-10-13T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112769"},"modified":"2026-10-14T13:22:03","modified_gmt":"2026-10-14T20:22:03","slug":"20261013-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20261013-00\/?p=112769\/","title":{"rendered":"C++ futures part 2: The mental model for <CODE>std::promise<\/CODE>, <CODE>std::packaged_task<\/CODE>"},"content":{"rendered":"<p><a title=\"C++ futures part 1: The mental model\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20261012-00\/?p=112767\"> Last time<\/a>, we looked at the &#8220;state&#8221; that powers the <code>std::promise<\/code>, <code>std::packaged_task<\/code>, <code>std::async<\/code>, <code>std::future<\/code>, and <code>std::shared<wbr \/>future<\/code> classes. Now we&#8217;ll see how that &#8220;state&#8221; (which I call the <code>source<\/code>) gets used and passed around.<\/p>\n<p>The lifetime of the <code>source<\/code> is managed by a <code>std::<wbr \/>shared_<wbr \/>ptr&lt;source&lt;T&gt;&gt;<\/code>. Everybody who has a reference to the source uses this shared pointer.<\/p>\n<p>The simplest case is <code>std::promise<\/code>. The operations on <code>std::promise<\/code> pretty much map directly to the operations on the <code>source<\/code> we laid out last time.<\/p>\n<p>The next more complicated case is the <code>std::<wbr \/>packaged_task<\/code>. This takes a callable and saves it for later. You can then call <code>get_future<\/code> to get a future and hand it to somebody as an IOU for &#8220;A value will appear here someday.&#8221;<\/p>\n<p>When you want to produce a value, you invoke the <code>packaged_task<\/code> with whatever parameters you want to pass to the original callable. The result of the invocation (either a value or an exception) is then stored in the <code>source<\/code> object, which can then be retrieved by the future.<\/p>\n<p>You can imagine a packaged task as just wrapping a promise:<\/p>\n<pre>template&lt;typename R, typename... Args&gt;\r\nclass packaged_task\r\n{\r\n    std::promise&lt;R&gt; p;\r\n    std::function&lt;R(Args...)&gt; func;\r\n\r\npublic:\r\n    template&lt;typename F&gt;\r\n    packaged_task(F&amp;&amp; f) : func(std::forward&lt;F&gt;(f)) {}\r\n\r\n    auto get_future() { return p.get_future(); }\r\n\r\n    void operator()(Args... args) {\r\n        try {\r\n            p.set_value(func(args...));\r\n        } catch (...) {\r\n            p.set_exception(std::current_exception());\r\n        }\r\n    }\r\n};\r\n<\/pre>\n<p>When you invoke it, it calls the stored callable with the arguments and puts the result in the promise.<\/p>\n<p>Okay, those were the easy cases of pushing values into the <code>source<\/code>. Next time, we&#8217;ll look at the messy case: <code>std::<wbr \/>async<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Building things out of the state.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-112769","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Building things out of the state.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112769","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=112769"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112769\/revisions"}],"predecessor-version":[{"id":112773,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112769\/revisions\/112773"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=112769"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112769"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}