使用PPL时,是否需要将析构函数与异步函数进行同步?
处理ViewModel销毁时的订阅清理
这是一个很典型的ViewModel生命周期管理场景——当View导航离开时,ViewModel可能会被销毁,这时候必须妥善清理订阅的事件,避免内存泄漏或者后续触发无效回调。你给出的析构实现已经很稳妥了,我来帮你拆解下逻辑,再补充一些相关的实践建议:
首先看你提供的析构函数代码:
MyViewModel::~MyViewModel() { if (m_subscription) { if (m_contentChangedToken.Value != 0) { m_subscription->ContentChanged -= m_contentChangedToken; m_contentChangedToken.Value = 0; } } }
核心逻辑解析
- 先检查
m_subscription是否有效(非空),这一步能避免空指针访问,是基础的安全校验 - 接着判断
m_contentChangedToken的Value是否不为0——这是在确认我们确实成功绑定过ContentChanged事件,不会执行无效的移除操作 - 调用
m_subscription->ContentChanged -= m_contentChangedToken,把之前注册的回调从事件中解绑,切断ViewModel和订阅源的关联 - 最后把
m_contentChangedToken.Value重置为0,明确标记这个订阅已经被清理,防止后续误操作
对应的ViewModel初始化流程
通常ViewModel创建后,会通过异步函数获取订阅实例并绑定事件,大致逻辑如下:
void MyViewModel::Initialize() { // 异步获取订阅实例 GetSubscriptionAsync().then([this](std::shared_ptr<Subscription> subscription) { m_subscription = subscription; if (m_subscription) { // 绑定ContentChanged事件,保存订阅令牌 m_contentChangedToken = m_subscription->ContentChanged += [this](const Content& newContent) { // 处理内容变化的业务逻辑 UpdateDisplayContent(newContent); }; } }); }
一些优化建议
- 封装清理逻辑:如果ViewModel有多个订阅需要清理,可以把订阅清理的代码封装成一个私有方法(比如
CleanupSubscriptions()),这样代码更整洁,也能在其他需要清理的场景(比如ViewModel的Uninitialize方法)复用 - 智能指针优化:如果用
std::shared_ptr管理m_subscription,可以省去手动空指针检查,但仍要保留令牌有效性的判断——因为智能指针非空不代表订阅令牌一定有效 - 异步安全防护:在异步获取订阅的回调中,建议用
std::weak_ptr捕获this,如果ViewModel在异步操作完成前就被销毁,能避免悬空指针访问:auto weakThis = std::weak_ptr<MyViewModel>(shared_from_this()); GetSubscriptionAsync().then([weakThis](std::shared_ptr<Subscription> subscription) { if (auto strongThis = weakThis.lock()) { strongThis->m_subscription = subscription; // 后续绑定事件逻辑... } });
内容的提问来源于stack exchange,提问作者Craig
相关产品推荐
相关产品推荐

