Учитывая следующий исходный код
#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;
}
}
Я ожидаю, что программа ответит Valid: 0
, При использовании g ++ 6.2.0 это так. Однако, используя MS VS2015 версии 14.0.25431.01 с обновлением 3, ответ Valid: 1
, Состояние будущего не считается недействительным после того, как исключение было передано в основной поток. Это ошибка или я сталкиваюсь с неопределенным поведением здесь?
Я, кажется, ошибка.
В соответствии с std::future::get
документация , valid()
должен вернуться false
после звонка get
,
Любое общее состояние освобождается.
valid()
являетсяfalse
после вызова этого метода.
Окунемся в реализацию VC ++ get
там есть ошибка:
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);
}
в принципе, _Retreived
также должен быть установлен в true
если _Exception
держит exception_ptr
, к моменту броска эта переменная никогда не устанавливается. кажется, что когда они проверяли это, они не проверяли готовое будущее,
только для неготового будущего, потому что последний не покажет эту ошибку.
Других решений пока нет …