You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++20协程自定义enumerable生成器出现use after free崩溃问题求助

问题根源

核心是协程悬挂+临时对象生命周期不匹配导致的悬垂指针访问,属于C++标准定义的未定义行为:
你的where是协程函数,且promise_type::initial_suspend返回std::suspend_always,所以where被调用时会立刻挂起,将构造好的enumerable对象返回给调用方,协程内部的遍历、过滤逻辑要等到第一次调用begin()恢复协程时才会执行。

崩溃场景的执行流程

  1. filtered_numbers函数内,numbers()返回一个临时enumerable<int>对象,调用它的where方法。
  2. where协程立刻挂起,返回新的enumerable<int>对象作为filtered_numbers的返回值。
  3. filtered_numbers函数执行结束,函数作用域内的所有临时对象(包括numbers()返回的上游enumerable)被析构。
  4. main函数中遍历filtered_numbers返回的对象,调用begin()恢复where协程,此时协程内访问的this指针(指向已经析构的上游enumerable对象)是悬垂指针,访问非法内存直接崩溃。

第二个main看似正常的原因

这只是未定义行为的“巧合”:你直接在range-for里写numbers().where(...),上游enumerable临时对象析构后,它占有的栈内存还没有被其他数据覆盖,所以where协程读取this->handle时还能拿到有效的地址值,刚好能正常执行。一旦程序复杂度提升,这块内存被其他逻辑改写,一样会崩溃。


可行解决方案

核心思路是将上游生成器的所有权转移到协程帧中,保证上游生成器的生命周期和where协程的生命周期一致,避免悬垂:

  1. 首先将enumerable改为move-only类型,补充移动构造、移动赋值和正确的资源释放逻辑:
enumerable(const enumerable&) = delete;
enumerable& operator=(const enumerable&) = delete;
enumerable(enumerable&& other) noexcept 
    : handle(std::exchange(other.handle, nullptr)) 
{}
enumerable& operator=(enumerable&& other) noexcept {
    if (this != &other) {
        if (handle) handle.destroy();
        handle = std::exchange(other.handle, nullptr);
    }
    return *this;
}
~enumerable()
{
    if (handle) {
        std::cout << "enumerable destructed: " << this << " : " << handle.address() << '\n';
        handle.destroy();
    }
}
  1. 修改where方法,仅允许右值调用,且将上游生成器移动到协程帧的局部变量中持有:
template<class Predicate>
enumerable<ReturnType> where(Predicate&& pred) &&
{
    // 将上游生成器移动到协程帧局部变量,生命周期和协程绑定
    auto upstream = std::move(*this);
    std::cout << "where: " << &upstream << " : " << upstream.handle.address()  << '\n';
    for (auto& i : upstream)
    {
        if(pred(i))
            co_yield i;
    }
}
// 可选:禁止左值调用where避免误用
template<class Predicate>
enumerable<ReturnType> where(Predicate&& pred) & = delete;

修改后不管是哪种调用场景,上游生成器都会被移动到where协程帧里持有,不会被提前析构,也不会出现悬垂指针问题,同时保留了initial_suspend返回std::suspend_always的惰性执行行为。


内容的提问来源于stack exchange,提问作者ahhhaghost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 09:54:03