{"id":41752164,"url":"https://github.com/zompi2/cppcorosample","last_synced_at":"2026-01-25T01:16:25.335Z","repository":{"id":214867701,"uuid":"737530681","full_name":"zompi2/cppcorosample","owner":"zompi2","description":"My understanding of C++20 coroutines with sample code.","archived":false,"fork":false,"pushed_at":"2024-06-12T05:33:08.000Z","size":25,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-06-12T11:19:44.657Z","etag":null,"topics":["coroutines","cpp","cpp20","documentation"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zompi2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-31T11:59:56.000Z","updated_at":"2024-06-12T05:33:11.000Z","dependencies_parsed_at":"2024-01-06T23:44:30.622Z","dependency_job_id":"932c0461-fc79-43ae-a721-b673a7fd170e","html_url":"https://github.com/zompi2/cppcorosample","commit_stats":null,"previous_names":["zompi2/cppcorosample"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zompi2/cppcorosample","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompi2%2Fcppcorosample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompi2%2Fcppcorosample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompi2%2Fcppcorosample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompi2%2Fcppcorosample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zompi2","download_url":"https://codeload.github.com/zompi2/cppcorosample/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompi2%2Fcppcorosample/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28740652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T22:12:27.248Z","status":"ssl_error","status_checked_at":"2026-01-24T22:12:10.529Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coroutines","cpp","cpp20","documentation"],"created_at":"2026-01-25T01:16:24.622Z","updated_at":"2026-01-25T01:16:25.324Z","avatar_url":"https://github.com/zompi2.png","language":null,"readme":"# C++20 coroutine samples\n\nThis is my understanding of [C++20 coroutines](https://en.cppreference.com/w/cpp/language/coroutines) with some samples.  \nI've written this document to help others (and myself) to understand what coroutines are, how to write them in C++ and when they are useful.   \nThis form of a documentation was inspired by the other github manuals, like [GAS](https://github.com/tranek/GASDocumentation) and [MASS](https://github.com/Megafunk/MassSample).  \nI wanted to create a collaborative document which should be easier to understand and to learn from than the official cpp reference, which I personally treat as a very good api reference, but not a good \"learn the basics\" material.  \nIf you notice any issue or have any idea how to improve the following examples feel free to write an issue or make a pull request.\n\n# Index\n* [What is a coroutine](#what-is-a-coroutine)\n* [The simpliest c++ coroutine example possible](#the-simpliest-c-coroutine-example-possible)\n* [Awaiters](#awaiters)\n* [Generators - coroutines returning values](#generators---coroutines-returning-values)\n* [Fibonnaci Generator](#fibonacci-generator)\n* [co_return value](#co_return-value)\n* [Camera Fade Out for Unreal Engine 5](#camera-fade-out-for-unreal-engine-5)\n* [More coroutines for UE5](#more-coroutines-for-ue5)\n* [Stability concerns](#stability-concerns)\n\n# What is a coroutine?\n\nA coroutine is a function which execution can be suspended (without suspending the rest of the code) and it can be resumed later. Such functionality is very useful if we have a function that needs to wait for something, for example for the response from http request or for the result of the other function that runs on another thread.  \nSure, we can use delegates, or lambdas instead of coroutines and get the similar behaviour, but having single line which can command the code to wait is more clear, readable and elegant solution.\n\n## Coroutines in other languages\n\nCoroutines have been a part of other languages for a long time, for example in C#. One of the most famous example is the code for [camera fade out for Unity game engine](https://docs.unity3d.com/Manual/Coroutines.html).\n\n```cs\nIEnumerator Fade()\n{\n    Color c = renderer.material.color;\n    for (float alpha = 1f; alpha \u003e= 0; alpha -= 0.1f)\n    {\n        c.a = alpha;\n        renderer.material.color = c;\n        yield return new WaitForSeconds(.1f);\n    }\n}\n```\n\nNormally the for-loop would simply set the material alpha to 0, but because this is a coroutine it will wait for 0.1 seconds after each for-loop iteration which will lead to a fluid and visible change of the material alpha. We can recognize that this is a coroutine because of the presence of the `yield` keyword. The `yield` suspends the whole function while the Unity built in coroutines system will resume it.\n\n## Coroutines in C++\nFunction is a coroutine in C++ when there is one of the following keywords inside:\n* `co_await` - it suspends the coroutine\n* `co_yield` - it suspends the coroutine and returns a value to the coroutine's caller\n* `co_return` - it completes the function with or without returning a value to the coroutine's caller\n\nCoroutine must return a coroutine handle which must satisfies a number of requirements, which will be explained below.\n\n[Back to index](#index)\n\n# The simpliest C++ coroutine example possible\n\nThis is (probably) the most simple C++ coroutine example possible. There is still a lot of happening there, but all of it will be explained below.\n\nThis code with comments is also inside the `Samples` directory here: [01_CoroSimpleExample.cpp](Samples/01_CoroSimpleExample.cpp)\n\n```c++\n#include \u003ciostream\u003e\n#include \u003ccoroutine\u003e\n\nstruct CoroPromise;\nstruct CoroHandle : std::coroutine_handle\u003cCoroPromise\u003e\n{\n    using promise_type = ::CoroPromise;\n\n    void await_resume() {}\n    bool await_ready() { return false; }\n    void await_suspend(std::coroutine_handle\u003cCoroPromise\u003e Handle) {};\n};\n\nstruct CoroPromise\n{\n    CoroHandle get_return_object() { return { CoroHandle::from_promise(*this) }; }\n    std::suspend_never initial_suspend() noexcept { return {}; }\n    std::suspend_never final_suspend() noexcept { return {}; }\n    void return_void() {}\n    void unhandled_exception() {}\n};\n\nCoroHandle CoroTest()\n{\n    std::cout \u003c\u003c \"CoroTest Before Suspend\\n\";\n    co_await CoroHandle();\n    std::cout \u003c\u003c \"CoroTest After Resume\\n\";\n}\n\nint main()\n{\n    CoroHandle handle = CoroTest();\n    std::cout \u003c\u003c \"CoroTest Resuming\\n\";\n    handle.resume();\n    return 0;\n}\n```\n\nThe output of this code will be:\n\n```\nCoroTest Before Suspend\nCoroTest Resuming\nCoroTest After Resume\n```\n\nNow let's go through all of this from top to bottom. First of all we have to define the coroutine. The coroutine is made of two parts:\n\n## Coroutine Handle\nThis is a structure based on the `std::coroutine_handle`. It allows to control the flow of the coroutine. It is always returned by the coroutine to it's caller. It will be used to resume the suspended coroutine later. The absolute minimum which needs to be defined inside the Handle is:\n* `promise_type` - this is a type of the coroutine Promise. What is a Promise will be explained later.\n* `await_resume` - this function is called when the coroutine is resumed. It can return `void` or a value of any type. When returning a value, the value can be obtained when calling `co_await` (e.g. `auto Value = co_await CoroHandle();`)\n* `await_ready` - this function is called before the coroutine suspension. If it returns `false` the coroutine will be suspended. If it returns `true` it will ignore the suspension.\n    \u003e Note: You can also write `void await_ready() {}` and it will behave the same as if it return `false`.\n* `await_suspend` - this function is called right after the suspension. It contains the actual instance of the handle of the suspended coroutine which might be stored and used later.\n\n## Coroutine Promise\nThe Promise structure contains a configuration of the coroutine, which defines how it should behave. The absolute minimum that must be defined here are:\n* `get_return_object` - function which constructs the coroutine handle.\n* `initial_suspend` - can return:\n    * `suspend_never` - the coroutine will not be suspended right at the beginning and it will be suspended when the `co_await` or `co_yield` is used.\n    * `suspend_always` - the coroutine will be suspended right at the beginning and it must be resumed to even start.\n* `final_suspend` - can return:\n    * `suspend_never` - the coroutine will not be suspended at the end of the coroutine. The coroutine will be destroyed right after it's finished.\n    * `suspend_always` - the coroutine will be suspended at the end. You must call `destroy()` function on the handle manually. Only with this setting you can check if the coroutine has finished by using the `done()` function on the handle.\n    \u003e Note: `initial_suspend` and `final_suspend` are one of the most important functions here, as they can control when the coroutine can be safely destroyed. We will utilize these functions later in more advanced coroutines.\n* `return_void` - this function is called when the `co_return` is used. The `co_return` is called by default when the function reaches the end.\n    \u003e Note: A Promise can also implement `return_value`. How to implement it is described **[here](#co_return-value)**.\n* `unhandled_exception` - used to catch any exception. To get more details about the catched extepction use `std::current_exception()` function.\n\n## Using the coroutine\nWe have a very simple coroutine defined, but how do we use it? In our example we have a function, which returns our coroutine handle, the `CoroHandle`. It uses `co_await` keyword to suspend it's execution. In the `main` program we call this function and get the `handle` to it. Later, we can use the `resume()` function on that handle to resume the suspended coroutine. And that's all!\n\n[Back to index](#index)\n\n# Awaiters\nAwaiters are an elegant way to define different awaiting logics using the same Handle and Promise, reducing the amount of boilerplate code you need to write.\n\nThe code below implements two different awaiters: `AwaiterA` and `AwaiterB`. They can be called when using `co_await` in the same coroutine which returns the same type of Handle.\n\n\u003e Note: You can notice that in the previous example the Handle was also an Awaiter. \n\nThis code with comments is also inside the `Samples` directory here: [02_CoroAwaiters.cpp](Samples/02_CoroAwaiters.cpp)\n\n```c++\n#include \u003ciostream\u003e\n#include \u003ccoroutine\u003e\n\nstruct CoroPromise;\nstruct CoroHandle : std::coroutine_handle\u003cCoroPromise\u003e\n{\n    using promise_type = ::CoroPromise;\n};\n\nstruct CoroPromise\n{\n    CoroHandle get_return_object() { return { CoroHandle::from_promise(*this) }; }\n    std::suspend_never initial_suspend() noexcept { return {}; }\n    std::suspend_never final_suspend() noexcept { return {}; }\n    void return_void() {}\n    void unhandled_exception() {}\n};\n\nclass AwaiterBase\n{\npublic:\n    void await_resume() {}\n    bool await_ready() { return false; }\n};\n\nclass AwaiterA : public AwaiterBase\n{\npublic:\n    void await_suspend(std::coroutine_handle\u003cCoroPromise\u003e Handle)\n    {\n        std::cout \u003c\u003c \"Suspended Using Awaiter A\\n\";\n    };\n};\n\nclass AwaiterB : public AwaiterBase\n{\npublic:\n    void await_suspend(std::coroutine_handle\u003cCoroPromise\u003e Handle)\n    {\n        std::cout \u003c\u003c \"Suspended Using Awaiter B\\n\";\n    };\n};\n\nCoroHandle CoroTest()\n{\n    std::cout \u003c\u003c \"CoroTest Before Suspend\\n\";\n    co_await AwaiterA();\n    std::cout \u003c\u003c \"CoroTest After First Resume\\n\";\n    co_await AwaiterB();\n    std::cout \u003c\u003c \"CoroTest After Second Resume\\n\";\n}\n\nint main()\n{\n    CoroHandle handle = CoroTest();\n    std::cout \u003c\u003c \"CoroTest First Resuming\\n\";\n    handle.resume();\n    std::cout \u003c\u003c \"CoroTest Second Resuming\\n\";\n    handle.resume();\n    return 0;\n}\n```\n\nThe output of this code will be:\n\n```\nCoroTest Before Suspend\nSuspended Using Awaiter A\nCoroTest First Resuming\nCoroTest After First Resume\nSuspended Using Awaiter B\nCoroTest Second Resuming\nCoroTest After Second Resume\n```\n\nAs you can see in this example we can call different Awaiters inside the same coroutine function.\n\n[Back to index](#index)\n\n# Generators - coroutines returning values\nJust suspending a running function is neat, but we can do more. Generators are a special type of Awaiters which, when suspended, can store a value, which can be used later outside of the coroutine.  \nLet's write a generic Generator and then use it to write some simple counting coroutine.\n\nThis code with comments is also inside the `Samples` directory here: [03_CoroGenerators.cpp](Samples/03_CoroGenerators.cpp)\n\n\n```c++\n#include \u003ciostream\u003e\n#include \u003ccoroutine\u003e\n\ntemplate\u003ctypename T\u003e\nstruct CoroGenerator\n{\n    struct CoroPromise;\n    using promise_type = CoroPromise;\n    using CoroHandle = std::coroutine_handle\u003cCoroPromise\u003e;\n\n    struct CoroPromise\n    {\n        T Value;\n\n        CoroGenerator get_return_object() { return { CoroGenerator(CoroHandle::from_promise(*this)) }; }\n        std::suspend_always initial_suspend() noexcept { return {}; }\n        std::suspend_always final_suspend() noexcept { return {}; }\n        void return_void() {}\n        void unhandled_exception() {}\n\n        template\u003cstd::convertible_to\u003cT\u003e From\u003e\n        std::suspend_always yield_value(From\u0026\u0026 from)\n        {\n            Value = std::forward\u003cFrom\u003e(from);\n            return {};\n        }\n    };\n\n    CoroHandle Handle;\n\n    explicit operator bool()\n    {\n        Handle.resume();\n        return !Handle.done();\n    }\n\n    T operator()()\n    {\n        return std::move(Handle.promise().Value);\n    }\n\n    CoroGenerator(CoroHandle InHandle) : Handle(InHandle) {}\n    ~CoroGenerator() { Handle.destroy(); }\n};\n\nCoroGenerator\u003cint\u003e CountToThree()\n{\n    co_yield 1;\n    co_yield 2;\n    co_yield 3;\n}\n\nint main()\n{\n    auto generator = CountToThree();\n    while (generator)\n    {\n        std::cout \u003c\u003c generator() \u003c\u003c \" \";\n    }\n    return 0;\n}\n```\n\nThe output of this code will be:\n\n```\n1 2 3\n```\n\nOnce again, there is a lot to cover. Let's go through this step by step.\n\n## Coroutine Promise for Generator\nThe Promise for a Generator is slightly different. You can notice few differences:  \n* `T Value` - Promise stores a value of a generic type. This value can be obtained later by a Generator.\n* `get_return_object` - doesn't return coroutine Handle, but a Generator with a coroutine Handle passed as an argument to the constructor.\n* `initial_suspend` and `final_suspend` returns `suspend_always`. This is important, because with such setup we have the full control over the coroutine flow.\n* `yield_value` - this function is called every time when `co_yield` is used. It stores the given value to the `Value` variable and returns `suspend_always` in order to suspend the function.\n\nThe Promise is defined inside the Generator struct in order to keep everything in one place and to avoid declaration loop.\n\n## Generator\nThe generator itself has few interesting parts as well:\n* `Handle` - this is the coroutine Handle saved from the Generator constructor.\n* `operator bool()` - is very handy for resuming the coroutine and checking if the coroutine has finished. To check if the coroutine is done we use `done()` function on the coroutine Handle. We can use it safely, because the `final_suspend` is set to `suspend_always`, so the coroutine Handle will not be destroyed automatically when the function is finished.\n* `operator()` -  will be used to get a stored value from the Promise.\n* Constructor - receives and remembers the coroutine Handle. The Generator construcor is used in `get_return_object` function in the Promise.\n* Destructor - explicitly destroys the coroutine Handle using `destroy()` function. It must be used, because the `final_suspend` is set to `suspend_always`, so it won't be destroyed automatically.\n\n## The Counter\n`CountToThree` coroutine returns the Generator which stores the `int` value. Every `co_yield` stores the given value inside of the Generator, which can be obtained later.\n\n## Using the Counter\nWhen Generator is constructed it automatically suspends, because of the `initial_suspend` set to `suspend_always`. Inside the while loop the `operator bool()` override is used to resume the Generator and check if the coroutine has already finished. Inside the while loop the `operator()` override is used to get lastly yielded value.\n\n[Back to index](#index)\n\n# Fibonacci Generator\n\nWe can write a slightly more advanced Generator. This one will yield every next number in the Fibonacci sequence.  \nThis code with comments is also inside the `Samples` directory here: [04_CoroFibonacciGenerator.cpp](Samples/04_CoroFibonacciGenerator.cpp)\n\n```c++\nCoroGenerator\u003cint\u003e FibonacciGenerator(const int Amount)\n{\n    if (Amount \u003c= 0)\n    {\n        co_return;\n    }\n\n    int n1 = 1;\n    int n2 = 1;\n    for (int i = 1; i \u003c= Amount; i++)\n    {\n        if (i \u003c 3)\n        {\n            co_yield 1;\n        }\n        else\n        {\n            const int tmp = n2;\n            n2 = n1 + n2;\n            n1 = tmp;\n            co_yield n2;\n        }\n    }\n}\n\nint main()\n{\n    auto generator = FibonacciGenerator(10);\n    while (generator)\n    {\n        std::cout \u003c\u003c generator() \u003c\u003c \" \";\n    }\n    return 0;\n}\n```\n\nThe output of this code will be:\n\n```\n1 1 2 3 5 8 13 21 34 55\n```\n\n[Back to index](#index)\n\n# co_return value\nA Coroutine Promise can also define `return_value` function, which will be called when `co_return` with a value is used. `return_value` and `return_void` can't be defined at the same time, only one of these functions can be used in the same Promise.  \n\n## co_return value in Awaiter\nIn Awaiter the `return_value` must be defined with the value type it can return. For `int` it will be:\n```cpp\nint ReturnValue;\nvoid return_value(int Value)\n{\n    ReturnValue = Value;\n}\n```\n\nTo get this value, get a Promise from the Handle and then get this value\n```cpp\nstd::cout \u003c\u003c \"Returned Value: \" \u003c\u003c handle.promise().ReturnValue \u003c\u003c \"\\n\";\n```\n\nImportant! Remember, that the `final_suspend()` of this awaiter must return `std::suspend_always`, otherwise the Handle after `co_return` will be invalid!\n\n## co_return value in Generator\nIn Generators defining `return_value` is very similar to defining `yield_value`.\n```cpp\ntemplate\u003cstd::convertible_to\u003cT\u003e From\u003e\nvoid return_value(From\u0026\u0026 from)\n{\n    Value = std::forward\u003cFrom\u003e(from);\n}\n```\nThe difference between `return_value` and `yield_value` is that `yield_value` will suspend the coroutine, while `return_value` will finish it.\n\n[Back to index](#index)\n\n# Camera Fade Out for Unreal Engine 5\n[At the beginning of this document](#coroutines-in-other-languages) I showed the example of the coroutine used in Unity game engine to fade out the camera. Let's write the same functionality but for Unreal Engine 5.3 which officially supports C++20, so it is possible to implement it.\n\nThis code with comments is also inside the `Samples` directory here: [05_CoroUE5FadeOut.cpp](Samples/05_CoroUE5FadeOut.cpp)\n\n```c++\n#include \u003ccoroutine\u003e\n#include \"Kismet/GameplayStatics.h\"\n\nstruct CoroPromise;\nstruct CoroHandle : std::coroutine_handle\u003cCoroPromise\u003e\n{\n    using promise_type = ::CoroPromise;\n};\n\nstruct CoroPromise\n{\n    CoroHandle get_return_object() { return { CoroHandle::from_promise(*this) }; }\n    std::suspend_never initial_suspend() noexcept { return {}; }\n    std::suspend_never final_suspend() noexcept { return {}; }\n    void return_void() {}\n    void unhandled_exception() {}\n};\n\nclass WaitSeconds\n{\nprivate:\n    float TimeRemaining;\n    std::coroutine_handle\u003cCoroPromise\u003e Handle;\n    FTSTicker::FDelegateHandle TickerHandle;\n\npublic:\n    WaitSeconds(float Time) : TimeRemaining(Time) {}\n\n    void await_resume() {}\n    bool await_ready() { return TimeRemaining \u003c= 0.f; }\n    void await_suspend(std::coroutine_handle\u003cCoroPromise\u003e CoroHandle)\n    {\n        Handle = CoroHandle;\n        TickerHandle = FTSTicker::GetCoreTicker().AddTicker(TEXT(\"CoroWaitSeconds\"), 0.f, [this](float DeltaTime) -\u003e bool\n        {\n            TimeRemaining -= DeltaTime;\n            if (TimeRemaining \u003c= 0.f)\n            {\n                FTSTicker::GetCoreTicker().RemoveTicker(TickerHandle);\n                Handle.resume();\n            }\n            return true;\n        });\n    };\n};\n\nCoroHandle CoroFadeOut()\n{\n    for (int32 Fade = 0; Fade \u003c= 100; Fade += 10)\n    {\n        if (GWorld)\n        {\n            if (APlayerCameraManager* CameraManager = UGameplayStatics::GetPlayerCameraManager(GWorld, 0))\n            {\n                CameraManager-\u003eSetManualCameraFade((float)Fade * .01f, FColor::Black, false);\n            }\n        }\n        co_await WaitSeconds(.1f);\n    }\n}\n```\n\nThe Handle and the Promise are the same as usual. To make it work we need a coroutine Awaiter, which will suspend the coroutine for a given amount of time and the actual coroutine which will fade out the camera.\n\n## Wait Seconds\nThis is a specific case of a coroutine Awaiter which resumes itself. It must somehow receive the coroutine Handle and the amount of seconds we want to wait.  \nThe time to wait is passed as an argument in the constructor.  \nThe coroutine Handle is obtained from the `await_suspend` function.  \nThe `await_suspend` function starts the Unreal Engine ticker which will resume the suspended coroutine using the received coroutine Handle.\n\n## Fade Out function\nThe fade out function changes the camera fade in a for loop in 10 steps every 0.1 second. You can notice the `co_await WaitSeconds(.1f)` after every loop iteration, which triggers our waiting coroutine Awaiter.\n\nIn order to use this function, simply call it in your project.\n\n[Back to index](#index)\n\n# More coroutines for UE5\nIf you are interested witch coroutines implementation for Unreal Engine 5 check out this amazing plugin [UE5Coro](https://github.com/landelare/ue5coro). Coroutines are also implemented in my UE plugin [Enhanced Code Flow](https://github.com/zompi2/UE4EnhancedCodeFlow) as well :)\n\n[Back to index](#index)\n\n# Stability concerns\n\nWhen using coroutines it is important to be aware that the coroutine doesn't track the lifetime of it's owner.   \n\nIf the owner of the coroutine has been destroyed while the coroutine is suspended, when something resumes the coroutine we will end up in an invalid place in memory.\n\nThe solution for game engines like Unreal Engine is to keep a soft reference to the owner inside the Awaiter and simply do not resume the coroutine if the reference becomes invalid.  \n\nFor pure c++ solutions it would require some sort of objects lifetime tracker.  \n\nThere is no bad side effect of keeping coroutines suspended forever, because they are stackless and all data required for their resume is stored inside a Handle, which is destroyed when going out of scope.\n\n[Back to index](#index)","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzompi2%2Fcppcorosample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzompi2%2Fcppcorosample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzompi2%2Fcppcorosample/lists"}