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

异步任务实现中std::shared_ptr在std::function回调间丢失导致on_success接收空指针的问题

问题排查与修复

让我们一步步拆解你的问题,核心问题出在async_task::do_async的循环逻辑上,同时还有个潜在的内存安全问题需要一并解决:

1. 致命的循环条件错误

先看你async_task::do_async里的循环代码:

do {
    try {
        do_async_tick();
    } catch (std::exception& e) {
        status->error = alloc<std::string>(e.what());
    }
} while (status->error != nullptr && result != nullptr);

这个循环条件完全写反了!你原本的意图应该是只要没有错误且结果还没生成,就持续执行do_async_tick,但现在的条件是error不为空 且 result不为空时才继续循环——这意味着:

  • 初始状态下status->error和result都是nullptr,循环直接退出,do_async_tick一次都不会执行;
  • 就算侥幸执行了一次tick,只要error或result有一个被赋值,循环就会终止,大概率result还没被正确赋值就进入了on_success回调,自然拿到空指针。

2. 潜在的引用悬空风险

你在std::async的lambda里用了[&, this]捕获,这里的&会捕获on_success和on_failure的引用。但textures::load是个成员函数,当它执行完毕返回后,这两个回调参数是函数的局部变量,对应的引用就会变成悬空引用,在后台线程调用时会触发未定义行为(虽然这不是你当前遇到的result为空的直接原因,但必须修复)。

修复方案

第一步:修正循环条件

把循环条件改成正确的逻辑——没有错误且未生成结果时继续执行:

do {
    try {
        do_async_tick();
    } catch (std::exception& e) {
        status->error = alloc<std::string>(e.what());
    }
// 修正:无错误且结果未生成时,持续执行tick
} while (status->error == nullptr && result == nullptr);

第二步:修复lambda捕获的悬空引用问题

将on_success和on_failure按值捕获,避免函数退出后引用失效:

std::async(std::launch::async, [this, on_success, on_failure] { 
    do {
        try {
            do_async_tick();
        } catch (std::exception& e) {
            status->error = alloc<std::string>(e.what());
        }
    } while (status->error == nullptr && result == nullptr);
    if (status->error != nullptr)
        on_failure(status);
    else {
        status->progress = 1.f;
        on_success(result);
    }
});

第三步:确保子类正确赋值result

最后要确认你的texture_loader_async::do_async_tick确实在纹理加载完成时给this->result赋值了,比如:

void texture_loader_async::do_async_tick() {
    // 执行分批次的纹理加载逻辑
    // ...
    // 当所有纹理加载完成时,赋值result
    if (is_all_textures_loaded()) {
        this->result = alloc<std::vector<std::pair<std::string, ptr<dx_texture>>>>();
        // 往result中填充加载好的纹理数据
        for (auto& texture_info : m_pending_textures) {
            auto tex = load_single_dx_texture(texture_info.path);
            this->result->emplace_back(texture_info.name, tex);
        }
    }
}

额外检查点

  • 确认progress_status的error成员初始值为nullptr,和你的代码定义一致;
  • 如果do_async_tick是分批次执行的,要保证每次调用都能推进加载进度,最终一定会给result赋值,避免无限循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 20:48:15