Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

futures, promises, and exceptions

std::promise<int> p1;
auto f = p1.get_future();

{
    std::promise<int> p2(std::move(pr));
}

bool valid = f.valid(); // true
f.wait(); // does not throw, or fail, but returns immediately
f.get(); // throws an exception

Is there any way to check if a future is going to throw before calling get? I hoped valid would check... I'm not really sure how to get valid to return false. Destroying the promise without setting a value doesn't do it.

like image 883
David Avatar asked Mar 17 '13 23:03

David


2 Answers

Is there any way to check if a future is going to throw before calling get?

No, as that would be somehow equal to receive the value stored in the future.

I hoped valid would check... I'm not really sure how to get valid to return false.

Valid will return true if the future refers to a shared state which can only be created by std::async, std::packaged_task or std::promise. A counterexample would be a default constructed std::future. Valid will also be false once you have called get or share on a valid(valid == true) future once.
Calling any other function than valid or the move-assignment operator on an invalid(valid == false) future is UB.

Destroying the promise without setting a value doesn't do it.

No, that as mentioned above is not the point of valid, as the future still refers to shared state just that the other side - the promise - wasn't fulfilled. If on destruction of a promise no value or exception was set, an exception to indicate the broken promise is set.

like image 138
Stephan Dollberg Avatar answered Sep 25 '22 02:09

Stephan Dollberg


Is there any way to check if a future is going to throw before calling get?

Your question is equivalent to:
Is there any way to check if a function is going to throw before calling it?

The answer to both questions is, in general, no.

Consider:

int func_that_might_throw()
{
  if (rand() % 2)
    throw 1;
  return 0;
}

std::future<int> f = std::async(&func_that_might_throw);

int result = f.get();

The async call could return a deferred function, in which case the function doesn't even run until you call get(), so in general there is no way to tell in advance whether the result will be a value or an exception. (You can detect a deferred function by calling f.wait_for(std::chrono::seconds(0)), but async might not return a deferred function, and in that case the function could still be running asynchronously when you try to check if it has a stored exception, so you'd have to check if it's ready and has a stored exception, so checking just gets very messy.)

A valid future with a shared state that is ready has a result, which is either a value or an exception. Both are valid results. If you don't want to handle exceptions then you should ensure an exception is not set in the shared state in the first place.

like image 34
Jonathan Wakely Avatar answered Sep 23 '22 02:09

Jonathan Wakely