std::unique_ptr с пользовательским удалителем для win32 LocalFree
У меня есть 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 ответа
Это выглядит правильно для меня. Вы можете сделать его более кратким, указав 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 ); } );
Объявление пользовательского удаления не очень красиво, использование 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 );
Я нахожу shared_ptr
немного более полезен в качестве общего средства защиты ресурсов. Он не требует, чтобы средство удаления входило в аргументы шаблона, и поэтому его можно легко обойти.
std::shared_ptr<LPWSTR> p(
::CommandLineToArgvW(L"cmd.exe p1 p2 p3", &n),
::LocalFree);
А как насчет ответа с использованием библиотек реализации Microsoft Windows (WIL)?
Прежде всего "установите" WIL (из терминала):
c:\dev>git clone https://github.com/microsoft/wil.git
А потом:
#include <Windows.h>
#include <iostream>
#include "c:/dev/wil/include/wil/resource.h"
int main(int argc, char* argv[])
{
{
int n = 0;
wil::unique_hlocal_ptr<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;
}