std :: unique_ptr с пользовательским удалителем для win32 LocalFree - PullRequest
14 голосов
/ 27 марта 2012

У меня есть win32 API CommandLineToArgvW, который возвращает LPWSTR* и предупреждает меня, что

CommandLineToArgvW выделяет блок непрерывной памяти для указатели на строки аргументов и на строки аргументов самих себя; вызывающее приложение должно освободить память, используемую список аргументов, когда он больше не нужен. Чтобы освободить память, используйте одиночный вызов функции LocalFree.

См http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx

Что такое идиоматический способ освобождения памяти в C ++ в указанном выше случае?

Я думал о std::unique_ptr с пользовательским удалителем, что-то вроде этого:

#include <Windows.h>
#include <memory>
#include <iostream>

template< class T >
struct Local_Del
{
   void operator()(T*p){::LocalFree(p);}
};

int main(int argc, char* argv[])
{
   {
      int n = 0;
      std::unique_ptr< LPWSTR, Local_Del< LPWSTR > > p( ::CommandLineToArgvW(L"cmd.exe p1 p2 p3",&n) );
      for ( int i = 0; i < n; i++ ) {
         std::wcout << p.get()[i] << L"\n";
      }
   }

    return 0;
}

Есть ли проблема в приведенном выше коде?

Ответы [ 3 ]

10 голосов
/ 27 марта 2012

Это выглядит правильно для меня. Вы можете сделать его более лаконичным, указав встроенное средство удаления unique_ptr вместо создания функтора для него.

std::unique_ptr<LPWSTR, HLOCAL(__stdcall *)(HLOCAL)> 
      p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ), ::LocalFree );

Или, если вы не хотите связываться с подписью и соглашениями о вызовах LocalFree, вы можете использовать лямбду для удаления.

std::unique_ptr<LPWSTR, void(*)(LPWSTR *)> 
      p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ), 
         [](LPWSTR *ptr){ ::LocalFree( ptr ); } );

Примечание: На момент написания этого ответа VS2010 была выпущенной версией VS. не поддерживает преобразование лямбд без захвата в указатели функций, поэтому вам придется использовать std::function во втором примере

std::unique_ptr<LPWSTR, std::function<void(LPWSTR *)>> 
      p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ), 
         [](LPWSTR *ptr){ ::LocalFree( ptr ); } );
6 голосов
/ 25 февраля 2013

Объявление пользовательского средства удаления не так красиво, использование decltype() быстрее.std::shared_ptr является альтернативой, но оно больше std::unique_ptr.Если вы не хотите делиться указателем, тогда возьмите unique_ptr.

std::unique_ptr<LPWSTR, decltype(::LocalFree)> 
     p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ), ::LocalFree );
5 голосов
/ 01 апреля 2012

Я считаю shared_ptr немного более полезным в качестве общего средства защиты ресурсов.Он не требует, чтобы средство удаления входило в аргументы шаблона, и поэтому его можно легко обойти.

std::shared_ptr<LPWSTR> p(
    ::CommandLineToArgvW(L"cmd.exe p1 p2 p3", &n),
    ::LocalFree);
...