Как переместить std :: unique_ptr между windows без риска утечки памяти? - PullRequest
0 голосов
/ 28 мая 2020

Я хочу сделать этот проект на C ++ и покончить с ним раз и навсегда: выберите mov ie из списка в одном окне и отобразите детали mov ie в другом окне.

Я уже пришел к решению Реми Лебо здесь и нашел его сообщение, потому что осознал то же ограничение, что и он: оно предоставляет необработанный указатель на утечку памяти.

( Извините, пожалуйста, за мой стиль кодирования).

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_ptr с MovieSelected() до фактического момента передачи, отправив ссылку на обработчик и используя std::move в ссылке.

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

Но я не могу понять, как получить ссылку из lParam в std::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. Все, что я получаю, - это постоянные ошибки компилятора (включая ненавистную теперь около std::remove_reference) и сбои. Приветствуется любое понимание.

Ответы [ 2 ]

2 голосов
/ 28 мая 2020

SendMessage и unique_ptr определенно не созданы друг для друга. Здесь я могу дать много подсказок, но лучше всего не использовать тайные указатели через сообщения HWND.

Я не знаю, что за UWM_SendMovieBean, но я предполагаю, что это обычная windows сообщение, основанное на WM_USER или RegisterWindowsMessage. То, что вы на самом деле делаете, звучит так, как будто вы пытаетесь сигнализировать другому компоненту кода с помощью SendMessage вместо формального контракта между поддерживающими классами обоих windows. Это не худшее, что когда-либо делалось, но с таким специализированным классом, как unique_ptr, это становится намного сложнее. row имеющаяся у вас структура данных. Затем ваше отправляемое сообщение просто отправляет uint__MovieKey как WPARAM или LPARAM вашего пользовательского сообщения.

Но если бы вы были в моей команде, и мы вместе создавали это приложение, я бы вас осмелился sh курс в Model-View-Presenter (и других MVC проектах), которые делают эти типы проектов более удобными в обслуживании.

1 голос
/ 01 июня 2020

Я получил ответ еще в двух попытках:

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

По сути, отправка адреса std::unique_ptr<MovieBean> означала, что я отправляю указатель, поэтому мне нужно было std::move(...), на что указывал указатель к. Работает нормально.

Мне это все еще кажется здравым: я оставляю MovieBean защищенным умным указателем, пока он «в полете». Фактически это просто передача по ссылке, которая не нарушает C ++ Core Rule 33: Возьмите параметр unique_ptr<widget>& в express, который функция переустанавливает виджет .

Существенное Проблема в этом использовании заключается в том, что мой обработчик сообщений также является сигналом для чтения обширной информации MovieBean в различные CommonControls MovieWindow. Обработчики сообщений должны быть быстрыми. Лучший подход - это то, что предлагает @ selb ie: формальный контракт между вспомогательными классами.

...