I have the win32 API CommandLineToArgvW
which returns a LPWSTR*
and
warns me that
CommandLineToArgvW
allocates a
I find shared_ptr
a bit more useful as a generic resource guard. It does not require the deleter to be the part of template arguments and as such can be easily passed around.
std::shared_ptr<LPWSTR> p(
::CommandLineToArgvW(L"cmd.exe p1 p2 p3", &n),
::LocalFree);
It looks correct to me. You could make it a little more succinct by specifying the unique_ptr
's deleter inline rather than creating a functor for it.
std::unique_ptr<LPWSTR, HLOCAL(__stdcall *)(HLOCAL)>
p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ), ::LocalFree );
Or, if you don't want to mess with LocalFree
's signature and calling conventions you can use a lambda to do the deletion.
std::unique_ptr<LPWSTR, void(*)(LPWSTR *)>
p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ),
[](LPWSTR *ptr){ ::LocalFree( ptr ); } );
Note: At the time this answer was first written, VS2010 was the released VS version available. It doesn't support conversion of capture-less lambdas to function pointers, so you'd have to use std::function
in the second example
std::unique_ptr<LPWSTR, std::function<void(LPWSTR *)>>
p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ),
[](LPWSTR *ptr){ ::LocalFree( ptr ); } );
And what about an answer using Microsoft Windows Implementation Libraries (WIL)?
First of all "install" WIL (from a terminal):
c:\dev>git clone https://github.com/microsoft/wil.git
And then:
#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;
}
Declaring of custom deleter is not so pretty, use of decltype()
is faster. std::shared_ptr
is an alternative, but it is larger than std::unique_ptr
. If you don't want to share a pointer, then take a unique_ptr
.
std::unique_ptr<LPWSTR, decltype(::LocalFree)>
p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ), ::LocalFree );