gpt4 book ai didi

c++ - 调用 get() 后 std::future 仍然有效(抛出异常)

转载 作者:可可西里 更新时间:2023-11-01 16:42:12 26 4
gpt4 key购买 nike

根据 cppreference ,在调用 std::future::get 之后:

valid() is false after a call to this method.

此外,来自 cplusplus.com :

Once the shared state is ready, the function unblocks and returns (or throws) releasing its shared state. This makes the future object no longer valid: this member function shall be called once at most for every future shared state.

异常安全下:

The function throws the exception stored in the shared state when the provider makes it ready by setting it to an exception. Note that in this case a basic guarantee is offered, with the future object being modified to no longer be a valid future (which is itself a valid state for object of this type, despite its name).

这两种描述都没有区分返回值的 get 调用和引发有关 future 对象失效的异常的调用。

但是,所描述的行为并不是我在这个示例代码中看到的:

#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 Update 2。这是编译器的错误,还是在出现异常时的正确行为?我一直无法找到与此相关的任何错误报告,因此不确定这是否是预期的行为。

编辑 - 实现调查

深入研究 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 检查之后)然后所有应该遵循其他逻辑。因此,编译器错误。

编辑 - 解决方法

我认为以下应该足以代替直接调用 get 直到实现修复:

template<typename T>
T getFromFuture(std::future<T>& fut)
{
try
{
return fut.get();
}
catch( ... )
{
fut = {};
throw;
}
}

最佳答案

我在 Linux 上使用 gcc 5.2.0 和 clang 3.7.0 编译——两次都是 64 位。运行程序总是导致

foo exception
This is expected.

在我看来,Visual 2013 对此处理不当。另见:

C++ §30.6.6/16-17

Throws: the stored exception, if an exception was stored in the shared state.

Postcondition: valid() == false.

后置条件在抛出之后提及,因此必须始终保持,即使抛出异常也是如此。至少这是我的解释,尽管我不会说标准语。

我想您应该也尝试使用 Visual Studio 2015 并报告一个错误,如果它显示相同的处理。

关于c++ - 调用 get() 后 std::future 仍然有效(抛出异常),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33899615/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com