According to cppreference, after calling std::future::get:
valid() is false after a call to this method.
Additionally, from 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.
And under Exception safety:
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).
Neither description makes a distinction between a call to get which returns a value versus one that throws an exception regarding the invalidation of the future object.
However, the described behavior is not what I'm seeing with this example code:
#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;
}
The output I see is:
foo exception
This is TOTALLY UNEXPECTED!!!
I'm using Visual Studio Premium 2013, Version 12.0.30501.00 Update 2. Is this a bug with the compiler or, in fact, correct behavior in the case of an exception? I've been unable to find any bug reports concerning this, so wasn't sure if it was expected behavior.
Edit - <future> implementation investigation
Digging into the std::future implementation a bit, the _Associated_state object is marked _Retrieved = true; AFTER checking and throwing the associated exception (if any):
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);
}
My guess is that the exception check and _Retrieved = true; should be swapped - the object should immediately be set as retrieved (after the _Get_only_once check) and then all other logic should follow. Ergo, compiler bug.
Edit - workaround
I think the following should suffice in lieu of directly calling get until a fix is implemented:
template<typename T>
T getFromFuture(std::future<T>& fut)
{
try
{
return fut.get();
}
catch( ... )
{
fut = {};
throw;
}
}
I compiled on Linux with gcc 5.2.0 and clang 3.7.0 -- both times with 64 Bit.
Running the program always results in
foo exception
This is expected.
It looks to me like Visual 2013 handles this incorrectly.
See also:
C++ ยง30.6.6/16-17
Throws: the stored exception, if an exception was stored in the shared state.
Postcondition: valid() == false.
The postcondition is mentioned after the throws and thus has to always hold, even if an exception is thrown. At least that is my interpretation, though I do not speak standardese.
I guess you should probably try also with Visual Studio 2015 and report a bug if that shows the same handling.
Related
Context:
I was reading the Transactional memory reference.
Some info are really unclear to me.
I run the code below in godbolt and I have a sense of what should happen but I want some confirmation or explanation of what is really expected to happen, not what I think should happen.
In the atomic_commit case:
If an exception is thrown, the transaction is committed normally.
That line raises some questions:
auto f() -> std::optional<int> {
static int i = 0;
std::optional<int> p;
atomic_commit {
//some memory ops happen here
++i;
throw std::runtime_error("I decide to fail here, for some reason");
p = i;
return p; // commit transaction
}
return std::nullopt;
}
int main() {
for (int retries = 0 ; retries < 10 ; ++retries) {
try {
auto r = f();
if (r) {
std::cout << r.value() << std::endl;
} else {
std::cout << "nope" << std::endl;
}
} catch (...) {
//handle the exception and maybe retry.
}
}
}
Question:
What happens exactly to the already registered data ? Is it taken back?
If two threads try to write at the same address, and the first one
failed to do so, what happens to the second? is the data corrupted?
In the case no exception is thrown, and two threads try to write in the same
address, what happens exactly?
As an added info, I mostly use the latest gcc.
Other thoughts:
On the other hand, the atomic_cancel seems to have an interesting behavior:
the values of all memory locations in the program that were modified by side effects of the operations of the atomic block are restored to the values they had at the time the start of the atomic block was executed, and the exception continues stack unwinding as usual
That would mean that all the data is copied first (may be faster than a lock).
It is the most natural behavior to me, except for the part that calling std::abort is quite rude.
But it doesn't matter, it is not always implemented anyway(gcc..).
Thanks
My coworkers and I think we have found a bug in Visual C++ 2012 and 2013 but we aren't sure. Should the call to std::current_exception in the following code be expected to return a non-null exception_ptr? It seems to on most other compilers we've tried:
#include <exception>
#include <stdexcept>
#include <iostream>
class A
{
public:
~A()
{
try
{
throw std::runtime_error("oh no");
}
catch (std::exception &)
{
std::clog << (bool)std::current_exception() << std::endl;
}
}
};
void foo ()
{
A aa;
throw std::runtime_error("oh no");
}
int main(int argc, char **)
{
try
{
foo();
}
catch(...)
{
}
return 0;
}
When run under Visual C++ we get "0" (false, which means the exception_ptr returned is null). Other compilers, such as g++, print "1".
cppreference says this about std::current_exception:
If called during exception handling (typically, in a catch clause), captures the current exception object and creates an std::exception_ptr that holds either a copy or a reference to that exception object (it is implementation-defined if a copy is made).
If the implementation of this function requires a call to new and the call fails, the returned pointer will hold a reference to an instance of std::bad_alloc
If the implementation of this function requires to copy the captured exception object and its copy constructor throws an exception, the returned pointer will hold a reference to the exception thrown. If the copy constructor of the thrown exception object also throws, the returned pointer may hold a reference to an instance of std::bad_exception to break the endless loop.
If the function is called when no exception is being handled, an empty std::exception_ptr is returned.
Throwing an exception unwind your stack which should call the destructor of your A class on your aa instance, in which you have a simple try/throw/catch bloc of code which catches the exception.
Of course it's not as authoritative as the standard, but it seems to me that g++/clang are right while visual is not (the other way around happens less often :p)
As confirmed by James McNellis, this is definitely a bug. I had the great pleasure of discovering it today.
In your case, the workaround is to call make_exception_ptr instead of current_exception in your handler:
~A()
{
try
{
throw std::runtime_error("oh no");
}
catch (std::exception & e)
{
std::clog << (bool)std::make_exception_ptr(e) << std::endl;
}
}
But I think we are out of luck for catch(...) clauses and a fix is really needed.
Edit1: I reported this bug in "connect" a long time ago. It can now be found on Developper Community.
Edit2: The bug was fixed in VS2019 16.3.
I am not able to understand how is it possible for std::async to store any exception, not just something derived from std::exception. I played around with the code below
#include <iostream>
#include <future>
#include <chrono>
void f()
{
std::cout << "\t\tIn f() we throw an exception" << std::endl;
throw 1; // throw an int
}
int main()
{
std::future<void> fut = std::async(std::launch::async, f);
std::cout << "Main thread sleeping 1s..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1)); // sleep one second
std::cout << "Main thread waking up" << std::endl;
try
{
fut.get();
}
catch(...)
{
std::cout << "We caught an exception!" << std::endl;
throw; // rethrow
}
}
I launch f() asynchronously, then throw an int inside f. Magically, this int is caught and stored by the future returned by std::async. I understand that is possible to catch(...) the exception in std::async, but how can the latter store it without knowing the exception type? The exception is not derived from some base class (in this case one perhaps can "clone" it via some Base::clone), but can be any exception. Can we somehow magically "deduce" the exception type?
To summarize, my question is:
How can we store an arbitrary exception inside an object then re-throw it at some later time, without knowing the exception type?
std::async could be implemented on top of std::thread and std::packaged_task.
std::packaged_task could be implemented (partly) on top of std::exception_ptr and related function (except that thread-exit ready function).
std::exception_ptr and related functions cannot be written in C++.
I'm not sure if this exactly answers your question, but this example might be helpful.
I compiled the following:
int main()
{
throw 1;
}
with the command
g++ -fdump-tree-gimple -std=c++11 main.cpp -o main
The gimple (gcc's intermediate output) is:
int main() ()
{
void * D.1970;
int D.1974;
D.1970 = __cxa_allocate_exception (4);
try
{
MEM[(int *)D.1970] = 1;
}
catch
{
__cxa_free_exception (D.1970);
}
__cxa_throw (D.1970, &_ZTIi, 0B);
D.1974 = 0;
return D.1974;
}
So it calls __cxa_throw with the address of the a symbol that represents a type. In this case the type is _ZTIi, which is the mangled type of an integer.
Types not available at compile time
The type symbols only need to be available at run time. In a dynamic library that is trying to hide as many symbols as it can, it needs to make sure that any exceptions that aren't caught and dealt with internally are available. For more info, see https://gcc.gnu.org/wiki/Visibility, particularly the section Problems with C++ exceptions (please read!).
It would be interesting to see how this worked between dynamic libraries compiled with different compilers that had different naming schemes.
I'm working through C++ Primer, 5th edition, and the author has presented an example to do with using shared_ptrs to manage resources from older libraries that could leak memory, to prevent them from doing so. I decided to create a test to see how it works, but my custom deleter doesn't get called after the exception is thrown and (deliberately) not caught:
#include <iostream>
#include <memory>
#include <string>
struct Connection {};
Connection* Connect(std::string host)
{
std::cout << "Connecting to " << host << std::endl;
return new Connection;
}
void Disconnect(Connection* connection)
{
std::cout << "Disconnected" << std::endl;
delete connection;
}
void EndConnection(Connection* connection)
{
std::cerr << "Calling disconnect." << std::endl << std::flush;
Disconnect(connection);
}
void AttemptLeak()
{
Connection* c = Connect("www.google.co.uk");
std::shared_ptr<Connection> connection(c, EndConnection);
// Intentionally let the exception bubble up.
throw;
}
int main()
{
AttemptLeak();
return 0;
}
It produces the following output:
Connecting to www.google.co.uk
My understanding is that when a function is exited, whether that's exiting normally or because of an exception, the local variables will all be destroyed. In this case, that should mean connection being destroyed when AttemptLeaks() exits, invoking its destructor, which should then call EndConnection(). Notice also that I'm using, and flushing, cerr, but that also didn't give any output.
Is there something wrong with my example, or my understanding?
Edit: While I already have the answer to this question, for anyone else that stumbles upon this in the future, my problem was with my understanding of how throw works. Although the answers below correctly state how to use it, I think it's best to explicitly make it clear that I was (incorrectly) trying to use it to 'generate' an unhandled exception, to test my code above.
Bare throw is intended for use inside catch blocks to rethrow a caught exception. If you use it outside a catch block, terminate() will be called and your program ends at once. See what does "throw;" outside a catch block do?
If you delete the throw-statement the shared_ptr connection will go out of scope and should call the deleter. If you have any doubts about the exception-safety of using a shared_ptr (I don't ;), you can explicitly throw an exception here by changing throw to throw 1.
The throw expression without an operand is intended for rethrowing the exception being currently handled. If no exception is being handled then std::terminate is called. In this situation stack unwinding does not take place, which is why the deleter is never being called. Change your code to the folowing:
void AttemptLeak()
{
Connection* c = Connect("www.google.co.uk");
std::shared_ptr<Connection> connection(c, EndConnection);
// Intentionally let the exception bubble up.
throw 42; // or preferably something defined in <stdexcept>
}
int main()
{
try {
AttemptLeak();
} catch(...) {
}
return 0;
}
Now the deleter will be called when the shared_ptr goes out of scope.
I have a rather odd occurrence happening that I haven't been able to nut out yet.
I have test case that is supposed to catch errors and return the appropriate error code from main, but /sometimes/ on test runs the program returns 0 even when the error code is non zero.
The exception class thrown is:
class exit_request {
public:
explicit exit_request(int code = 0) : m_code(code) {}
int code() const { return m_code; }
private:
int m_code;
};
The test case code is:
int main(int argc, char* argv[])
{
try {
// Do some test case stuff
// Eventually, due to the supplied command line arguments,
// we expect an exit_request() to be thrown from within
// library code.
}
catch (exit_request& exp) {
std::cout << "Exit Request:" << exp.code() << std::endl;
return exp.code();
}
catch (std::exception& err) {
std::cout << "Error: " << err.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
In many runs of this test case, everything works as expected: The exit_request() exception is thrown, caught, exp.code() is printed (its value is 2), and the return code from the process is 2.
However, very occasionally, the return code from the process is 0 (i.e. no failure), even though exp.code() is printed as 2.
Can anyone help explain a situation in which this can occur? i.e. the return value from main is changed from non-zero to zero before the process exits?
This is occurring on Windows 7 (x64), with MSVC++ 2010 Express, building a x86 (32-bit) application. I have not seen this odd failure on any of our other Windows or Linux platforms, or compilers, but that doesn't necessarily mean it couldn't happen in those environments.
If you have any atexit handlers that call exit(0), or any static-storage-duration objects whose destructors do that, it might explain what you're seeing. They get executed after your return statement. It's undefined behavior, which could explain why you only see it happen sometimes.
Maybe you are not throwing the exception correctly...
I mean that from the function called or processing done in try block, you are throwing exception of some other type.
Try to write a default catch block for that.