我想升级我的 MFC 生产代码以使用 std::shared_ptr
调用其他窗口或线程时的智能指针。此类电话是 SendMessage
, PostMessage
和 PostThreadMessage
哪个通过 wparam
和 lparam
和分别是 unsigned int
和 long
.目前,我创建一个类对象,新建一个对象,调用传递一个指向该对象的指针,在接收端使用该对象,然后将其删除。
自 shared_ptr
在我的其余代码中效果很好,我想至少探索一下为什么我不能对 Windows 调用做同样的事情的原因。
当前通话:
auto myParams = new MyParams(value1, value2, value3);
PostThreadMessage(MSG_ID, 0, reinterpret_cast< LPARAM >( myParams );
ReceivingMethod::OnMsgId( WPARAM wParam, LPARAM lParam)
{
auto myParams = reinterpret_cast< MyParams * >( lParam );
... // use object
delete myParams;
}
到类似 C++11 的智能指针调用:
std::shared_ptr< MyParams > myParams( new MyParams( value1, value2, value3 ) );
PostThreadMessage( MSG_ID, 0, ???myParams??? );
ReceivingMethod::OnMsgId( WPARAM wParam, LPARAM lParam )
{
auto myParams = ???lParam???;
... // use object
}
编辑1:
@Remy Lebeau:这是修改为使用 unique_ptr 传递方法的示例代码,但是,传递对象时我的代码中存在泄漏:
struct Logger
{
Logger()
{
errorLogger = ( ErrorLogger * )AfxBeginThread( RUNTIME_CLASS( ErrorLogger ), THREAD_PRIORITY_BELOW_NORMAL );
}
~Logger()
{
// gets properly dtor'ed upon app exit
}
void MakeLogMsg( ... );
ErrorLogger * errorLogger;
std::unique_ptr< LogParams > logParams;
};
Logger logger;
std::recursive_mutex logParamsRecursiveMu; // because of multiple requests to lock from same thread
struct ErrorLogger : public CWinThread
{
ErrorLogger()
{
}
~ErrorLogger()
{
// gets properly dtor'ed before logger upon app exit
}
afx_msg void OnLog( WPARAM wParam, LPARAM lParam );
};
void Logger::MakeLogMsg( ... )
{
// construct msg from logparams
// make msg smart object using unique ptr and send to errorlogger thread queue
logParams = std::make_unique< LogParams >();
// set logparams
// with the addition of the mutex guard, the leaks are gone
logParamsRecursiveMu.lock();
logger.errorLogger->PostThreadMessage( ONLOG_MSG, 0, reinterpret_cast< LPARAM >( logParams.get() ) );
logParams.release(); // no longer owns object
logParamsRecursiveMu.unlock();
}
void ErrorLogger::OnLog( WPARAM wParam, LPARAM lParam )
{
std::unique_ptr< LogParams > logParams( reinterpret_cast< LogParams * >( lParam ) );
}
请注意,当我注释掉 unique_ptr 的传递时,泄漏消失了。我的代码与您使用这种方法并有效的代码有何不同?
编辑2:
关于
@Remy Lebeau
's answer显示如何std::unique_ptr
可以用来代替 std::shared_ptr
,我在下面的评论中表示“......没有额外的对象要实现。没有明显的缺点。”。嗯,这并不完全正确。 MyParams
必须为每种不同类型的消息创建对象。有些应用程序可能只有几种类型,但有些应用程序可能有 100 个或更多。每次我想在另一边执行一个函数时,我都必须制作一个新的结构,它有一个构造函数,它接受目标调用的所有参数。如果有很多,则实现起来非常繁琐且难以维护。我认为仅通过传递参数就可以消除结构构建阶段。
显然有新的 C++1x 结构可以帮助实现这一点。一个可能是
std::forward_as_tuple
其中“构造一个对 args 中参数的引用元组,适合作为参数转发给函数。”对于我的应用程序,我通过模板化
MyParams
解决了这个问题,但对于任何想要避免添加大量结构的人来说,他可能想考虑使用元组等。编辑 3:@RemyLebeau 的答案 1 和@rtischer8277 的答案 5 都是正确的。不幸的是,StackOverflow 无法识别多个正确答案。此 StackOverflow 限制反射(reflect)了一种有缺陷的心理语言学假设,即语言上下文对于同一语言组是通用的,但事实并非如此。 (参见 Roger Harris 关于固定代码语言神话的“综合语言学简介”,第 34 页)。在回复我的原始帖子时,@RemyLebeau 根据显示
new
的已发布代码描述的上下文回答了该问题。编辑 MyParams
(有关更多解释,请参阅编辑 2:)。后来在答案 5 (rtischer8277) 中,我根据问题的原始措辞自己回答了这个问题,该问题询问是否 std::shared_ptr
可以使用 PostThreadMessage
跨线程使用.作为一个合理的结果,我已将正确答案重新分配给@RemyLebeau,这是第一个正确答案。编辑4:
我在这篇文章中添加了第三个合法答案。请参阅以@Remy Lebeau 和@rtischer8277 开头的第 6 个答案,到目前为止,它们已为我的原始帖子提交了两个答案……这个方案的效果是把跨线程访问变成了概念上简单的RPC(远程过程调用)。尽管此答案显示了如何使用
future
为了控制所有权和同步,它没有展示如何使用任意数量的参数创建消息对象,这些参数可以安全地用于 PostThreadMessage 调用的任一侧。 StackOverflow's Answer to issue passing a parameter pack over a legacy function signature using forward_as_tuple 中解决了该功能.
最佳答案
由于消息参数必须超过调用范围,因此使用 shared_ptr
没有多大意义。在本例中,作为源 shared_ptr
最有可能在处理消息之前超出范围。我建议使用 unique_ptr
相反,您可以 release()
指针在飞行中,然后在处理消息后获得它的新所有权:
SendingMethod::SendMsgId( ... )
{
...
std::unique_ptr<MyParams> myParams( new MyParams(value1, value2, value3) );
if (PostThreadMessage(MSG_ID, 0, reinterpret_cast<LPARAM>(myParams.get()))
myParams.release();
...
}
ReceivingMethod::OnMsgId( WPARAM wParam, LPARAM lParam)
{
std::unique_ptr<MyParams> myParams( reinterpret_cast<MyParams*>(lParam) );
... // use object
}
关于c++11 - 如何使用 PostThreadMessage 使用 shared_ptr?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25667226/