异步任务实现中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
相关产品推荐
相关产品推荐

