[英]std::future still valid after calling get() (which throws an exception)
根据cppreference ,在调用std::future::get
:
调用此方法后,valid()为false。
另外,来自cplusplus.com :
共享状态准备就绪后,该函数将解除阻塞并返回(或抛出)释放其共享状态。 这使得将来的对象不再有效:对于每个未来的共享状态,该成员函数最多应被调用一次。
并在异常安全下 :
当提供程序通过将其设置为异常使其准备就绪时,该函数会抛出存储在共享状态中的异常。 请注意,在这种情况下,会提供基本保证,将来的对象修改为不再是有效的未来(对于此类型的对象,它本身就是一个有效的状态,尽管它的名称)。
这两个描述都没有区分对get
返回值的调用与抛出有关未来对象失效的异常的调用。
但是,所描述的行为不是我在这个示例代码中看到的:
#include <chrono>
#include <future>
#include <iostream>
#include <stdexcept>
int foo()
{
throw std::runtime_error("foo exception");
}
int main()
{
std::future<int> futInt;
futInt = std::async(std::launch::async, []() { return foo(); });
while( !(futInt.valid() && futInt.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) )
;
if( futInt.valid() )
{
int val;
try
{
val = futInt.get();
}
catch( const std::exception& e )
{
std::cout << e.what() << std::endl;
}
}
if( futInt.valid() )
{
std::cout << "This is TOTALLY UNEXPECTED!!!" << std::endl;
}
else
{
std::cout << "This is expected." << std::endl;
}
return 0;
}
我看到的输出是:
foo exception
This is TOTALLY UNEXPECTED!!!
我正在使用Visual Studio Premium 2013,版本12.0.30501.00更新2.这是编译器的错误,或者事实上,在异常情况下是否正确? 我一直无法找到有关此问题的任何错误报告,所以不确定这是否是预期的行为。
编辑 - <future>实施调查
深入研究std::future
实现, _Associated_state
对象标记为_Retrieved = true;
AFTER检查和投掷相关的异常(如果有的话):
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);
}
我的猜测是异常检查和_Retrieved = true;
应该交换 - 应该立即将对象设置为检索(在_Get_only_once
检查之后),然后应该遵循所有其他逻辑。 Ergo,编译错误。
编辑 - 解决方法
我认为以下内容应该足以直接调用get
直到实现修复:
template<typename T>
T getFromFuture(std::future<T>& fut)
{
try
{
return fut.get();
}
catch( ... )
{
fut = {};
throw;
}
}
我使用gcc 5.2.0和clang 3.7.0在Linux上编译 - 两次都使用64位。 运行程序总是会导致
foo exception
This is expected.
它看起来像Visual 2013错误地处理这个问题。 也可以看看:
C ++§30.6.6/ 16-17
抛出:存储的异常,如果异常存储在共享状态中。
后置条件:
valid() == false
。
抛出后提到后置条件,因此即使抛出异常也必须始终保持。 至少这是我的解释,虽然我不说标准。
我想您应该尝试使用Visual Studio 2015并报告错误,如果显示相同的处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.