2012-03-27 30 views
13

Ho API Win32 CommandLineToArgvW che restituisce un LPWSTR* e mi avverte chestd :: unique_ptr con deleter personalizzato per win32 LocalFree

CommandLineToArgvW alloca un blocco di memoria contigua per puntatori alle corde argomento, e per le stringhe argomento ; l'applicazione chiamante deve liberare la memoria utilizzata dall'elenco degli argomenti quando non è più necessaria. Per liberare la memoria, utilizzare una singola chiamata alla funzione LocalFree.

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

Che è un C++ modo idiomatico per liberare la memoria nel caso di cui sopra?

Stavo pensando ad un std::unique_ptr con un deleter personalizzato, qualcosa di simile:

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

C'è qualche problema nel codice di cui sopra?

risposta

10

Sembra corretto per me. Potresti renderlo un po 'più sintetico specificando in linea il deleter del unique_ptr invece di creare un funtore per esso.

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

Oppure, se non si vuole pasticciare con firma e convenzioni di chiamata è possibile utilizzare una lambda a fare la cancellazione LocalFree s'.

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

Nota: Al momento questa risposta è stato scritto, VS2010 è stato il rilascio VS versione disponibile. Si doesn't support conversione di lambda-cattura meno di funzionare puntatori, in modo che avrebbe dovuto utilizzare std::function nel secondo esempio

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

Non è necessario 'std :: function' per l'ultimo esempio, penso: i lambda stateless sono convertibili in puntatori di funzione. Cioè 'Std :: unique_ptr p (...)' – MSalters

+0

@MSalters ho provato questo, ma non è riuscito a compilare sotto VC10 e g ++ 4.6.2. messaggio di errore del primo è 'l'errore C2664: 'std :: :: unique_ptr <_Ty,_Dx> unique_ptr (wchar_t *, void (__stdcall * const &) (LPWSTR *))': non può convertire il parametro 2 da 'anonymous-namespace' :: ' a 'void (__stdcall * const &) (LPWSTR *)' ' – Praetorian

+0

@MSalters Lei ha ragione, lambda captureless può essere convertito in un puntatore a funzione, in modo da' std :: function' non è necessario. Tuttavia, VC10 [non implementa questo] (https://connect.microsoft.com/VisualStudio/feedback/details/572138).Non so come l'ho incasinato la prima volta che ho provato con g ++ ma sicuramente funziona. – Praetorian

4

trovo shared_ptr un po 'più utile come guardia risorsa generica. Non richiede che il deleter sia la parte degli argomenti del template e come tale può essere facilmente passato in giro.

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

grazie per la risposta. Non sono sicuro di preferire una sintassi semplice sulla semantica giusta. IMHO shared_ptr non è adatto nel mio caso. Vedi http://www2.research.att.com/~bs/C++0xFAQ.html#std-shared_ptr vs http://www2.research.att.com/~bs/C++0xFAQ.html#std -unique_ptr –

+0

È vero, non stai cercando di passare il tuo puntatore, ma potrebbe essere utile conoscere le tecniche correlate. –

6

Dichiarando di deleter personalizzato non è così bella, l'uso di decltype() è più veloce. std::shared_ptr è un'alternativa, ma è più grande di std::unique_ptr. Se non vuoi condividere un puntatore, prendi uno unique_ptr.

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

In Visual Studio 2010, deve essere 'std :: unique_ptr ', altrimenti la compilazione fallirà con errore criptico. Questo perché 'decltype (:: LocalFree)' non è un tipo di puntatore a funzione, ma un tipo di funzione. –

Problemi correlati