coro-throwing.cpp (1840B)
1 #include "coroutine_owner.hpp" 2 3 #include <stdexcept> 4 #include <utility> 5 #include <iostream> 6 7 struct coro 8 { 9 struct promise_type 10 { 11 coro get_return_object() { return {*this}; } 12 std::suspend_never initial_suspend() { return {}; } 13 std::suspend_always final_suspend() noexcept { return {}; } 14 void unhandled_exception() noexcept { e = std::current_exception(); } 15 void return_void() noexcept {} 16 std::exception_ptr e; 17 }; 18 19 coroutine_owner<promise_type> h; 20 21 void result() 22 { 23 if (not *h) 24 throw std::logic_error("cannot get result() from empty coroutine"); 25 else if (not h->done()) 26 throw std::logic_error("cannot get result() from unfinished coroutine"); 27 else if (auto e = std::exchange(h->promise().e, {})) 28 std::rethrow_exception(e); 29 std::cerr << "coroutine finished successfully.\n"; 30 } 31 32 coro() = default; 33 coro(promise_type& p) 34 : h{std::coroutine_handle<promise_type>::from_promise(p)} 35 {} 36 ~coro() 37 { 38 cancel(); 39 } 40 void cancel() noexcept 41 { 42 if (auto x = std::exchange(h, {}); *x) 43 if (auto& e = x->promise().e) 44 try 45 { 46 std::rethrow_exception(e); 47 } catch (std::exception const& e) 48 { 49 std::cerr << "Dropped exception: '" << e.what() << "'\n"; 50 } catch (...) { 51 std::cerr << "Dropped exception\n"; 52 } 53 } 54 coro(coro const&) = delete; 55 coro& operator =(coro const&) = delete; 56 coro(coro&& old) 57 : h{std::move(old.h)} 58 {} 59 coro& operator =(coro&& old) 60 { 61 cancel(); 62 h = std::exchange(old.h, {}); 63 return *this; 64 } 65 }; 66 67 coro mycoro(bool success) 68 { 69 if (success) 70 co_return; 71 throw std::runtime_error("hi"); 72 } 73 74 int main() try 75 { 76 auto a = mycoro(true); 77 a.result(); 78 a = mycoro(false); 79 auto c = mycoro(false); 80 auto c2 = std::move(c); 81 a = std::move(c2); 82 a.result(); 83 } 84 catch (std::exception const& e) 85 { 86 std::cerr << "Caught exception: '" << e.what() << "'\n"; 87 return 1; 88 }