作为事件接收器使用的CCmdTarget的正确生命周期管理是什么?
What is the proper lifetime management for a CCmdTarget used as an event sink?
我遵循给出的"如何在基于mfc的COM客户端中创建接收器接口"的微软示例代码,以便在c++ (VC6)中创建事件接收器。事件源是一个。net程序集,通过COM互操作公开其功能。
让我感到不适的是样本的最后一个音符:
因为CMySink是在堆上创建的,所以请确保将其删除到避免内存泄漏。
有几件事我要注意:
- GetIDispatch和AfxConnectAdvise/AfxConnectUnadvise的自动递增/递减参数设置为FALSE,因此我假设sink的内部引用计数在整个练习中保持不变。 OnFinalRelease方法在练习中没有显示,所以我假设它是删除sink实例的默认行为。
记住示例文本中的最后一个注意事项,我的清理代码看起来像这样:
//Get a pointer to sinks IUnknown, no AddRef.
LPUNKNOWN pUnkSink = m_pSink->GetIDispatch(FALSE);
//Terminate a connection between source and sink.
//m_pUnkSrc is IUnknown of server obtained by CoCreateInstance().
//m_dwCookie is a value obtained through AfxConnectionAdvise().
AfxConnectionUnadvise(m_pUnkSrc, IID_MYEVENT, pUnkSink, FALSE,
m_dwCookie);
delete m_pUnkSink;
这个示例中的代码在一个循环中运行,该循环包括创建接收器、将其连接起来、等待几个事件,然后将其拆除并删除。我看到的是,经过几轮循环后,OnFinalRelease突然被调用。不仅如此,OnFinalRelease在当前循环迭代的接收器实例上被调用(而不是循环的先前迭代使用的某个先前实例)。结果是当前接收器在当前循环执行下被删除,并导致一堆空指针错误。
我尝试删除删除m_pUnkSink的调用。结果是OnFinalRelease永远不会被调用。这给我留下了一个内存泄漏,因为所有这些接收器的实例都累积在堆中。
我想我可能可以在循环的每次迭代中重用相同的接收器实例,但我很好奇正确的生命周期管理是什么。我是否需要在删除实例自己和重写OnFinalRelease之间做出明确的选择,不做任何事情,而不是永远删除自己,总是期望OnFinalRelease执行删除?一个比另一个更受欢迎吗?
OnFinalRelease
的默认实现是删除对象。最好将CCmdTarget
子类化以获得消息映射和事件钩子,并创建自己的类,该类可以保留在所需的所有处理范围内,然后只在最后删除一次。您可以添加一个回调或通知消息来表示正在完成的所有操作,以清理您的对象。
如果没有其他原因,你不希望在循环中从堆中分配和删除内存。
更新:
如果默认实现是不需要的,就像MFC的情况一样,那么你最好的选择是覆盖virtual OnFinalRelease
,让它什么都不做,而不是像在CCmdTarget
中那样调用delete this;
。然后就完全由你自己来删除你的对象并清理。如果你有c++ 0x支持,我会让你的sink类引用计数对象,或者把它放在像std::unique_ptr
这样的智能指针中。
- 如何在共享库的整个生命周期内存储数据
- 如何理解句子的生命周期始于对e的评估
- 它解决了什么问题,对于非真空初始化,生命周期在初始化之前就开始了
- Go/C++gRPC客户端通道和存根生命周期
- 如何将"this"的生命周期移动到C++中的另一个对象中?
- 是否可以通过使用移动/交换 c++11 来延长返回的临时变量的生命周期
- 使用对象的生命周期作为设置器的安全性
- 临时人员的生命周期传递给函数
- 我想知道在构造函数中初始化变量时的生命周期
- Lua 用户数据生命周期管理
- 如何使用 epoll(void* event.data.ptr) 管理 Connection 的生命周期
- C++引用的生命周期
- 在堆栈上有一个对象,而不是在函数的整个生命周期内
- 在 Boost ASIO 服务器中处理生命周期
- C++ lambda 生命周期
- 使用互斥锁跟踪另一个应用的生命周期
- QSharedPointer 或 std::shared_ptr 的生命周期
- 来自async_resolve的 boost::asio::ip::tcp::resolver::iterator 的生命周期是多久?
- 如何调整属于类的唯一指针的字符数组的大小.它必须在程序的整个生命周期中保持活力
- 延长 std::tuple<int&,int> 的生命周期,方法是将其分配给 const std::tuple<int, int>&