I have implemented a c++ coroutine framework so that I can coawait my own coroutines and script sequences like so:
co_await obj->move_to(....)
obj->face(LEFT);
co_await wait(15);
This would be a coroutine that I update one frame at a time from my main program, and would execute the directions in order as if they are blocking.
This is the implementation of my coroutines for reference:
struct Script {
struct suspend_maybe {
    bool suspend;
    bool await_ready() noexcept { return !suspend; }
    void await_suspend(std::coroutine_handle<> c) noexcept {}
    void await_resume() noexcept { }
};
struct promise_type {
    std::coroutine_handle<promise_type> child;
    std::coroutine_handle<promise_type> caller;
    bool cancelled = false;
    void cancel() { cancelled = true; }
    Script get_return_object() {
        return { std::coroutine_handle<Script::promise_type>::from_promise(*this) };
    }
    suspend_maybe initial_suspend() noexcept {
        return { !caller };
    }
    std::suspend_always final_suspend() noexcept {
        return {};
    }
    void unhandled_exception() {}
    void return_void() {}
};
bool await_ready() noexcept { return false; }
bool await_suspend(std::coroutine_handle<Script::promise_type> c) noexcept {
    c.promise().child = h_;
    h_.promise().caller = c;
    return true;
}
void await_resume() noexcept { }
std::coroutine_handle<Script::promise_type> h_;
Script(std::coroutine_handle<Script::promise_type> h) :h_{ h } { }
operator std::coroutine_handle<Script::promise_type>() const { return h_; }
// Step update the coroutine, managing its control flow
void update() {
    auto& child = h_.promise().child;
    if (child && !(child.done() || child.promise().cancelled)) {
        child.promise().get_return_object().update();
    }
    else {
        if (child && (child.done() || child.promise().cancelled)) {
            child.destroy();
            child = nullptr;
        }
        h_.resume();
    }
}
};
 typedef std::coroutine_handle<Script::promise_type> CHandle;
And this is how I update the coroutines that are spawned by the script, in the main loop per every frame of rendering:
CHandle ScriptPlayer::spawn(CHandle script) {
    scripts.push_back(script);
    return script;
}
void ScriptPlayer::update() {
  for (int i = 0; i < static_cast<int>(scripts.size()); ) {
      Script{ scripts[i] }.update();
      if (play_next_script) break;
      // Check completion
      if (scripts[i].done() || scripts[i].promise().cancelled) {
          scripts[i].destroy();
          scripts.erase(scripts.begin() + i);
      }
      else i++;
  }
}
Then somewhere I have a lambda that I use to generate a Script and spawn it to the vector of coroutines that I update every frame:
auto terminate = [](ScriptPlayer* player, Object* fx) -> Script {
   co_await fx->wait_animation();
   player->destroy_object(fx);
}(player, fx);
player->spawn(terminate);
If I use the lambda function parameters like I did above, everything works perfectly fine. On the other hand, if I try to use the captures like so:
auto terminate = [player, fx]() -> Script {
   co_await fx->wait_animation();
   player->destroy_object(fx);
}();
player->spawn(terminate);
The whole thing crashes within "wait_animation" during runtime with a completely corrupt coroutine stack frame.
Why? I thought passing pointers by value through the captures would be the same as passing the same pointers through function arguments?