c++11 - 如何使用 PostThreadMessage 使用 shared_ptr?

标签 c++11 mfc tuples future sendmessage

我想升级我的 MFC 生产代码以使用 std::shared_ptr调用其他窗口或线程时的智能指针。此类电话是 SendMessage , PostMessagePostThreadMessage哪个通过 wparamlparam和分别是 unsigned intlong .目前,我创建一个类对象,新建一个对象,调用传递一个指向该对象的指针,在接收端使用该对象,然后将其删除。

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/

相关文章:

c++ - 将对象重置为初始状态的模式

c++ - 如何将 std::copy 字符串复制到具有 std::string 字段的结构

c++ - 从电子邮件正文调用 Win32 应用程序

c++ - 解析日期/时间字符串问题

python - 为什么元组比 Python 中的列表快?

c++ - 并行运行时采用迭代器对的函数不起作用

c++ - 从可变参数模板创建 std::array

c++ - 如何在 C++ 中初始化 wchar_t 指针变量?

python - 这不是一个元组吗?

typescript - 如何将联合类型转换为元组类型