How can I use shared_ptr using PostThreadMessage?(如何使用 PostThreadMessage 使用 shared_ptr?)
问题描述
我想升级我的 MFC 生产代码以在调用其他窗口或线程时使用 std::shared_ptr
智能指针.此类调用是 SendMessage
、PostMessage
和 PostThreadMessage
,它们通过 wparam
和 lparam
并且分别是 unsigned int
和 long
.目前,我创建一个类对象,新建一个对象,调用传递一个指向该对象的指针,在接收端使用该对象,然后将其删除.
I would like to upgrade my MFC production code to use the std::shared_ptr
smart pointer when calling other windows or threads. Such calls are SendMessage
, PostMessage
and PostThreadMessage
which pass wparam
and lparam
and which respectively are an unsigned int
and long
. Currently, I create a class object, new an object, make the call passing a pointer to the object, use the object on the receiving end and then delete it.
由于 shared_ptr
在我的其余代码中运行良好,我想至少探索一下为什么我不能对 Windows 调用执行相同操作.
Since shared_ptr
works so well in the rest of my code I wanted to at least explore the reasons why I can't do the same for windows calls.
当前通话:
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 的智能指针调用:
to a C++11-like smart pointer call:
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 传递方法的示例代码,但是,在传递对象时,我的代码中存在泄漏:
@Remy Lebeau: Here is the sample code revised to use the unique_ptr passing approach, however, there are leaks in my code when passing the object:
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 的传递时,泄漏消失了.我的代码与您使用这种方法并有效的代码有何不同?
Notice that when I comment out the passing of the unique_ptr, the leaks disappear. How does my code differ from your code that uses this approach and works?
关于 @Remy Lebeau
的回答显示如何使用 std::unique_ptr
代替 std::shared_ptr
,我在下面的评论中指出,……没有额外的对象要实现.没有明显的缺点.".好吧,这并不完全正确.MyParams
对象必须为每种不同类型的消息创建.有些应用程序可能只有几种类型,但有些可能有 100 种或更多.每次我想在另一边执行一个函数时,我都必须制作一个新的结构,它有一个构造函数,它接受目标调用的所有参数.如果有很多,实施起来非常繁琐且难以维护.
With regard to @Remy Lebeau
‘s answer showing how std::unique_ptr
could be used instead of std::shared_ptr
, I stated in a comment below that there were "…no extra objects to implement. No obvious cons.". Well, that is not quite true. The MyParams
object has to be created for each different type of message. Some apps might only have a few types, but some might have 100s or more. Each time I want to execute a function on the other side I have to craft a new struct which has a constructor that takes all the arguments of the destination call. Very tedious to implement and hard to maintain if there are many.
我认为只需传递参数就可以消除结构构建阶段.
I think that it would be possible to eliminate that struct-building phase by merely passing the arguments.
显然有新的 C++1x 结构可以帮助实现这一点.一个可能是 std::forward_as_tuple
,它构造一个对 args 中的参数的引用的元组,适合作为函数的参数转发."
Apparently there are new C++1x constructs that can help accomplish this. One is perhaps the std::forward_as_tuple
which "Constructs a tuple of references to the arguments in args suitable for forwarding as an argument to a function."
对于我的应用,我通过模板化 MyParams
解决了这个问题,但对于任何想要避免添加大量结构的人来说,他可能想考虑使用元组等.
For my app I solved the problem by templatizing MyParams
, but for anyone whose wants to avoid adding a lot of structs, he may want to look at using tuples and the like.
编辑 3:@RemyLebeau 的答案 1 和 @rtischer8277 的答案 5 都是正确的.不幸的是,StackOverflow 不能识别多个正确答案.这个 StackOverflow 限制反映了一个有缺陷的心理语言学假设,即语言上下文对于同一语言组是通用的,但事实并非如此.(参见 Roger Harris 关于固定代码语言神话的综合语言学简介",第 34 页).在回复我最初的帖子时,@RemyLebeau 根据发布的代码所描述的上下文回答了这个问题,该代码显示了 new
ed MyParams
(请参阅编辑 2:了解更多说明).很久以后,在答案 5 (rtischer8277) 中,我自己根据问题的原始措辞回答了这个问题,该问题询问是否可以使用 PostThreadMessage
跨线程使用 std::shared_ptr
.作为一个合理的结果,我已将正确答案重新分配给@RemyLebeau,它是第一个正确答案.
Edit 3: Both @RemyLebeau's answer number 1 and @rtischer8277’s answer number 5 are correct. Unfortunately, StackOverflow doesn’t recognize multiple correct answers. This StackOverflow limitation reflects a flawed PsychoLinguistic assumption that linguistic context is universal for the same language group, which it is not. (see "Introduction to Integrational Linguistics" by Roger Harris on the fixed-code language myth, p.34). In response to my original posting, @RemyLebeau answered the question based on the context described by the posted code that shows a new
ed MyParams
(see Edit 2: for more explanation). Much later in Answer 5 (rtischer8277), I answered the question myself based on the original wording of the question which asked if std::shared_ptr
could be used across threads using PostThreadMessage
. As a reasonable consequence, I have re-assigned the correct answer back to @RemyLebeau it being the first correct answer.
我在这篇文章中添加了第三个合法答案.请参阅以 @Remy Lebeau 和 @rtischer8277 开头的第 6 个答案,到目前为止,我已为我的原始帖子提交了两个答案…….这个方案的效果是把跨线程访问变成了概念上简单的RPC(远程过程调用).虽然这个答案展示了如何使用 future
来控制所有权和同步,但它没有展示如何创建一个可以安全使用的具有任意数量参数的消息对象在 PostThreadMessage 调用的任一侧.该功能已在 StackOverflow 的 Answer 中解决,以发布 使用 forward_as_tuple 将参数包传递给旧函数签名.
I added a third legitimate answer to this posting. See the 6th Answer beginning with @Remy Lebeau and @rtischer8277 have so far submitted two answers to my original posting…. The effect of this solution is to turn cross-thread access into the conceptually simple RPC (remote procedure call). Although this Answer shows how to use a future
to control ownership and synchronization, it does not show how to create a message object with an arbitrary number of parameters that can safely be used on either side of the PostThreadMessage call. That functionality is addressed in StackOverflow’s Answer to issue passing a parameter pack over a legacy function signature using forward_as_tuple.
推荐答案
由于消息参数必须超过调用范围,所以在这个例子中使用 shared_ptr
没有多大意义,因为source shared_ptr
最有可能在消息被处理之前超出范围.我建议改用 unique_ptr
,这样您就可以在指针运行时 release()
指针,然后在处理完消息后获得它的新所有权:
Since the message parameters have to outlive the calling scope, it does not make much sense to use shared_ptr
in this example, as the source shared_ptr
is most likely to go out of scope before the message is processed. I would suggest using unique_ptr
instead, so that you can release()
the pointer while it is in flight, and then obtain new ownership of it once the message is processed:
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
}
这篇关于如何使用 PostThreadMessage 使用 shared_ptr?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何使用 PostThreadMessage 使用 shared_ptr?
基础教程推荐
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 从 std::cin 读取密码 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01