c++ - std::shared_ptr 在 std::function 回调之间丢失
问题描述
我有以下异步任务实现
template <class T>
class async_task {
public:
ptr<progress_status> do_async(std::function<void(ptr<T>)> on_success, std::function<void(ptr<progress_status>)> on_failure);
protected:
virtual void do_async_tick() = 0;
ptr<progress_status> status = nullptr;
ptr<T> result = nullptr;
};
template<class T>
inline ptr<progress_status> async_task<T>::do_async(std::function<void(ptr<T>)> on_success, std::function<void(ptr<progress_status>)> on_failure)
{
status = alloc<progress_status>();
std::async(std::launch::async, [&, this] {
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);
}
});
return status;
}
我实现了这个类来使用它来加载一些纹理
class texture_loader_async : public async_task<std::vector<std::pair<std::string, ptr<dx_texture>>>> {
public:
virtual void do_async_tick() override;
};
class textures : public resource_bag<dx_texture>, public singleton<textures>
{
friend class singleton<textures>;
public:
virtual ptr<progress_status> load(std::function<void()> on_success, std::function<void()> on_failure) override;
private:
texture_loader_async loader;
};
随着实施
ptr<progress_status> textures::load(std::function<void()> on_success, std::function<void()> on_failure)
{
return loader.do_async(
[&](auto textures) {
for (auto& pair : *textures) {
add_resource(pair.first.c_str(), pair.second);
}
on_success();
},
[&](auto status) {
on_failure();
}
);
}
这里ptr
=std::shared_ptr
和alloc
=std::make_shared
我的问题是在 textures::load 中的 on_success 事件中出现的异步任务结果为空,即使这不应该是可能的丢失并将 nullptr 发送到 on_success ...
解决方案
[&]
通过引用捕获。[&]
除非生成的 lambda 和所有副本将在当前范围结束之前被销毁,否则切勿使用。
您将它传递给do_async
,这似乎不太可能在当前范围结束时破坏 lambdas(以及它们的所有副本)。
所以你的代码遵循悬空引用。
简单的更改是更改为[=]
; 但实际上,当您进行异步工作时,请明确列出所有捕获。我什至建议不要捕获this
.
当然,在函数体中,您调用std::async
并丢弃结果,结果会立即阻塞,直到异步任务完成。所以就是这样。但是,如果您解决了这个问题,您就会遇到参考捕获问题。
我怀疑您的代码不是一个最小的完整可验证示例,并且正在发生其他事情。
该status->error
代码也是不好的代码气味。异步代码和那里的主线程之间似乎没有任何同步(我的意思是,也许你有一个疯狂的operator->
过载,但我对此表示怀疑)。
推荐阅读
- .net - 用于 Azure 服务总线的 MassTransit 批量接收消息以避免限制
- javascript - 如何计算在 Javascript 中创建的对象的数量?
- reactjs - Formik 提交带有空字段的表单
- javascript - 从打字稿中的数据填充列中的索引值(Angular / React)
- wordpress - Wordpress Multisite - 成熟的选项 - 它有什么作用?
- hive - 如何在 HiveQL 中将列和行作为标题
- botkit - botkit google hangouts chat 是 0.7 版还是 google hangouts chat 支持打字指示器?
- ios - 在 iOS 应用程序中设置 Microsoft Azure SAML 2.0
- three.js - 覆盖网格对于 Forge 3D 查看器中的某些材质颜色是透明的
- tensorflow - 在 Beagle Bone Black 中安装张量流