https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60966
--- Comment #25 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Leon Timmermans from comment #24) > > get_future() is non-const, set_value() is non-const. > > I can see your point from a C++ point of view, but this doesn't make sense > from a usable threading point of view. IMHO, the whole point of abstractions > such as promises is to isolate the user from such issues. Within reason yes, but not entirely. You can't expect to safely assign to the same std::promise in two threads for example. Anyway, that's not the real issue here, the example can be fixed to avoid such race conditions but still demonstrate the problem: #include <future> #include <thread> #include <vector> struct DummyTask { DummyTask(int id) : id_(id) {} int id_; std::promise<void> pr; }; const int THREADS = 100; void run_task(DummyTask* task) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); task->pr.set_value(); } void wait_for_task(std::future<void> fut) { fut.wait(); } int main() { std::vector<const DummyTask*> tasks; std::vector<std::thread> threads; std::vector<std::future<void>> futures; for (int i = 0; i < THREADS; ++i) { DummyTask* task = new DummyTask(i); tasks.push_back(task); futures.push_back(task->pr.get_future()); threads.emplace_back(run_task, task); } for (int i = 0; i < THREADS; ++i) { wait_for_task(std::move(futures[i])); // Because we returned from wait_for_task for this task, run_task is surely done. // No one else is referring to the task. So, even before threads[i]->join(), // it should be safe to delete it now. delete tasks[i]; // but here you get an invalid read! } for (int i = 0; i < THREADS; ++i) { threads[i].join(); } }