Given the following source code
#include <thread>
#include <future>
#include <iostream>
#include <string>
#include <chrono>
int main() {
auto task = std::async(std::launch::async, [] {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
throw std::runtime_error("error");
});
try {
while (task.wait_for(std::chrono::seconds(0)) !=std::future_status::ready)
{
std::cout << "Not ready: " << std::endl;
}
task.get();
}
catch (const std::exception& e)
{
std::cout << "Valid: " << task.valid() << std::endl;
}
}
I would expect, that the program will response with Valid: 0
. Using g++ 6.2.0 this is the case. However, using MS VS2015 Version 14.0.25431.01 Update 3 the response is Valid: 1
. The state of the future is not invalidaded, after the exception was propagated to the main thread. Is this a bug or am i running into undefined behaviour here?
I appears to be a bug.
According to std::future::get
documentation , valid()
should return false
after a call to get
.
Any shared state is released.
valid()
isfalse
after a call to this method.
Digging a bit into VC++ implementation of get
, there is a bug there:
virtual _Ty& _Get_value(bool _Get_only_once)
{ // return the stored result or throw stored exception
unique_lock<mutex> _Lock(_Mtx);
if (_Get_only_once && _Retrieved)
_Throw_future_error(
make_error_code(future_errc::future_already_retrieved));
if (_Exception)
_Rethrow_future_exception(_Exception);
_Retrieved = true;
_Maybe_run_deferred_function(_Lock);
while (!_Ready)
_Cond.wait(_Lock);
if (_Exception)
_Rethrow_future_exception(_Exception);
return (_Result);
}
basically, _Retreived
should also be set to true
if _Exception
holds an exception_ptr
. by the time of throwing, this variable is never set. it appears that when they tested it, they didn't test for a ready future,
only for non ready future, because the latter will not show this bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With