2012-03-27 18 views
13

tengo la API de Win32 CommandLineToArgvW que devuelve un LPWSTR* y me advierte questd :: unique_ptr con Deleter personalizado para LocalFree Win32

CommandLineToArgvW asigna un bloque de memoria contigua para punteros a las cadenas de argumentos, y para las cadenas de argumentos ellos mismos; la aplicación de llamada debe liberar la memoria utilizada por la lista de argumentos cuando ya no sea necesaria. Para liberar la memoria, use una llamada única a la función LocalFree.

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

¿Qué es un C++ forma idiomática para liberar la memoria en el caso anterior?

yo estaba pensando a un std::unique_ptr con un Deleter costumbre, algo así:

#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; 
} 

¿Hay algún problema en el código anterior?

Respuesta

10

Parece correcto para mí. Podrías hacerlo un poco más conciso especificando el eliminador de unique_ptr en línea en lugar de crear un functor para él.

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

O, si usted no quiere meterse con firma y convenciones de llamada se puede utilizar una lambda para hacer la eliminación LocalFree 's.

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

Nota: En el momento en que esta respuesta fue escrito por primera vez, VS2010 fue puesto en libertad el VS versión disponible. Se doesn't support conversión de lambdas de captura-menos para funcionar punteros, por lo que tendría que utilizar std::function en el segundo ejemplo

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

No necesita 'std :: function' para el último ejemplo, creo: los lambda sin estado son convertibles en punteros a funciones. Es decir. 'Std :: unique_ptr p (...)' – MSalters

+0

@MSalters Yo probé eso, pero no lograron compilar bajo VC10 y g ++ 4.6.2. mensaje de error de los primeros es 'C2664 de error: 'std :: :: unique_ptr <_Ty,_Dx> unique_ptr (wchar_t *, void (* const __stdcall Y) (LPWSTR *))': no ​​se puede convertir el parámetro 2 de 'anonymous-espacio de nombres' :: ' a 'void (* const __stdcall y) (LPWSTR *)' ' – Praetorian

+0

@MSalters Estás en lo correcto, lambdas captureless se pueden convertir a un puntero de función, por lo que' std :: function' no es necesario. Sin embargo, VC10 [no implementa esto] (https://connect.microsoft.com/VisualStudio/feedback/details/572138).No sé cómo lo estropeé la primera vez que probé con g ++, pero definitivamente funciona. – Praetorian

4

encuentro shared_ptr un poco más útil como un guardia de recurso genérico. No requiere que el eliminador forme parte de los argumentos de la plantilla y, como tal, se puede pasar fácilmente.

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

gracias por su respuesta. No estoy tan seguro de que prefiera la sintaxis fácil sobre la semántica correcta. IMHO shared_ptr no es adecuado en mi caso. Ver http://www2.research.att.com/~bs/C++xFAQ.html#std-shared_ptr vs http://www2.research.att.com/~bs/C++0xFAQ.html#std -unique_ptr –

+0

Es cierto que no está buscando pasar su puntero, pero podría ser útil conocer las técnicas relacionadas. –

6

Declarar de Deleter personalizado no es tan bonita, el uso de decltype() es más rápido. std::shared_ptr es una alternativa, pero es más grande que std::unique_ptr. Si no desea compartir un puntero, tome un unique_ptr.

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

En Visual Studio 2010, tiene que ser 'std :: unique_ptr ', o la compilación fallará con un error críptico. Eso es porque 'decltype (:: LocalFree)' no es un tipo de puntero a función, sino un tipo de función. –

Cuestiones relacionadas