2012-03-27 15 views
13

mam Win32 API CommandLineToArgvW która zwraca LPWSTR* i ostrzega mnie, żestd :: unique_ptr z niestandardowym Deleter dla Win32 LocalFree

CommandLineToArgvW alokuje blok pamięci ciągłej dla wskaźniki do ciągów argumentów, a dla samych łańcuchów argumentów ; aplikacja wywołująca musi zwolnić pamięć używaną przez listę argumentów , gdy nie jest już potrzebna. Aby zwolnić pamięć, użyj pojedynczego połączenia z funkcją LocalFree.

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

Co to jest C++ idiomatyczne sposób, aby zwolnić pamięć w powyższym przypadku?

Myślałam do std::unique_ptr z niestandardowym Deleter, coś takiego:

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

Czy istnieje jakiś problem w powyższym kodzie?

Odpowiedz

10

Dla mnie wygląda prawidłowo. Możesz uczynić to nieco bardziej zwięzłym, określając wbudowany delter w stylu unique_ptr, zamiast tworzyć dla niego funktor.

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

Lub, jeśli nie chcą zadzierać z podpisem i wywołanie konwencje można użyć lambda robić usunięcie LocalFree „s.

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

Uwaga: W tym czasie po raz pierwszy odpowiedź pisemną, VS2010 został uwolniony VS dostępnej wersji. To doesn't support konwersja lambdas przechwytywania mniej funkcjonować wskaźniki, więc trzeba by użyć std::function w drugim przykładzie

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

Nie potrzebujesz 'std :: function' dla ostatniego przykładu, myślę: stateless lambda są zamienne na wskaźniki funkcji. To znaczy. 'std :: unique_ptr p (...)' – MSalters

+0

@ MSalters Próbowałem tego, ale nie udało się go skompilować pod VC10 i g ++ 4.6.2. Pierwszy z komunikatów o błędach to "błąd C2664:" std :: unique_ptr <_Ty,_Dx> :: unique_ptr (wchar_t *, void (__stdcall * const &) (LPWSTR *)) ': nie można przekonwertować parametru 2 z' anonymous-namespace ':: ' to 'void (__stdcall * const &) (LPWSTR *)' ' – Praetorian

+0

@MSalters Masz rację, przechwytywania lambdas można przekonwertować na wskaźnik funkcji, więc' std :: function' nie jest konieczne. Jednak VC10 [nie implementuje tego] (https://connect.microsoft.com/VisualStudio/feedback/details/572138).Nie wiem, jak to zrobiłem, gdy próbowałem po raz pierwszy z g ++, ale na pewno działa. – Praetorian

4

znajdę shared_ptr nieco bardziej przydatny jako ogólne straży zasobów. Nie wymaga, aby deleter był częścią argumentów szablonu i jako taki można go łatwo przekazać.

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

dziękuję za odpowiedź. Nie jestem pewien, czy wolałbym prostą składnię ponad odpowiednią semantyczną. IMHO shared_ptr nie jest odpowiednie w moim przypadku. Zobacz 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

To prawda, że ​​nie chcesz przekazać swojej wskazówki, ale warto wiedzieć o powiązanych technikach. –

6

Deklarowanie niestandardowych Deleter nie jest tak ładna, wykorzystanie decltype() jest szybsze. std::shared_ptr to alternatywa, ale jest większa niż std::unique_ptr. Jeśli nie chcesz udostępniać wskaźnika, wykonaj unique_ptr.

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

W Visual Studio 2010 musi to być 'std :: unique_ptr ' lub kompilacja zakończy się niepowodzeniem z tajemniczym błędem. Dzieje się tak, ponieważ 'decltype (:: LocalFree)' nie jest typem wskaźnika funkcji, ale typem funkcji. –

Powiązane problemy