首页 > 解决方案 > 如何在窗口之间移动 std::unique_ptr 而不会冒内存泄漏的风险?

问题描述

我想在 C++ 中完成这个项目并一劳永逸地完成它:从一个窗口的列表中选择一部电影,然后在另一个窗口中显示电影的详细信息。

我已经在这里找到了Remy Lebeau 的解决方案并找到了他的帖子,因为我意识到了他所做的同样的限制:它将原始指针暴露给内存泄漏。

(请原谅我的编码风格)。

MoviesWindow::MovieSelected( const unsigned int uint__MovieKey )
{   ...
    std::unique_ptr<MovieBean> uptr__MovieBean = std::make_unique...
    ...
    uptr__MovieBean->SetMovieTitle(   row["MovieTitle"]   );
    uptr__MovieBean->SetYearReleased( row["YearReleased"] );
    ...
    SendMessage( hwnd__MovieWindow, UWM_SendMovieBean, 0, (LPARAM) uptr__MovieBean->get() );
    ...
}

幸运的是,我有一个优势SendMessage():在消息处理程序返回之前它不会结束(释放std::unique_ptr),并且消息处理程序的工作是克隆MovieBean.

MovieWindow::HandleUwmSendMovieBean( const HWND hwnd__MovieWindow, const UINT uint__WindowMessage, const WPARAM wParam, const LPARAM lParam )
{   UPTR__MovieBean = std::move( (*((MovieBean*) lParam).Clone() );
    ...
}

似乎正确的方法是通过发送对处理程序的引用并在引用上使用,将std::unique_ptrwith的所有权保留到实际传输时刻。MovieSelected()std::move

MoviesWindow::MovieSelected( const unsigned int uint__MovieKey )
{   ...
    SendMessage( hwnd__MovieWindow, UWM_SendMovieBean, 0, (LPARAM) &uptr__MovieBean );
    ...
}

但我无法弄清楚如何将参考lParamstd::move. 这似乎是一个,但不是。

MovieWindow::HandleUwmSendMovieBean( const HWND hwnd__MovieWindow, const UINT uint__WindowMessage, const WPARAM wParam, const LPARAM lParam )
{ UPTR__NewMovieBean  = std::move( reinterpret_cast<std::unique_ptr<MovieBean>*>( lParam ) );
    ...
}

我已经尝试了所有我能想到的组合,并确保发送的地址是接收并提供给 std::move 的地址。我得到的只是不断的编译器错误(包括一个现在非常讨厌的 about std::remove_reference)和崩溃。任何见解将不胜感激。

标签: c++windowsunique-ptr

解决方案


SendMessage并且unique_ptr绝对不是为彼此而生的。我可以在这里给出很多提示,但最好的办法是不要通过 HWND 消息走私智能指针。

我不知道 a 是什么UWM_SendMovieBean,但我猜这是您基于 offWM_USERRegisterWindowsMessage. 因此,您真正在做的事情听起来像是在尝试使用 SendMessage 向另一个代码组件发出信号,而不是两个窗口的支持类之间的正式合同。这样做并不是最糟糕的事情,但是对于像 unique_ptr 这样专门的类,它变得更加难以实现。

便宜又容易做的事情是让两个窗口共享row您拥有的数据结构。然后您的发送消息只是将uint__MovieKey作为您的自定义消息的 WPARAM 或 LPARAM 发送。

但是,如果您在我的团队中,并且我们正在一起构建这个应用程序,我会为您提供 Model-View-Presenter(和其他 MVC 设计)的速成课程,使这些类型的功能设计更易于维护。


推荐阅读