2012-03-27 20 views
13

私はLPWSTR*を返し、 がのstd :: win32のLocalFreeのカスタム削除手段とunique_ptrを

CommandLineToArgvWは、引数文字列に のポインタのための連続したメモリのブロックを割り当てていることを私に警告したWin32 API CommandLineToArgvWを持っている、と引数の文字列は です。呼び出し元のアプリケーションは、不要になったときに、 引数リストで使用されるメモリを解放する必要があります。メモリを解放するには、LocalFreeファンクションへの単一コールを で呼び出します。

を参照してください http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx

C++上記の場合のメモリを解放する慣用的な方法は何ですか?

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

上記のコードのいずれかの問題があります:

私は、カスタム削除手段とstd::unique_ptrにそのようなことを考えていましたか?

答えて

10

それは私に見えます。ファンクタを作成するのではなく、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リリースされました。関数ポインタへのキャプチャレスラムダのそれdoesn't support変換、2番目の例では

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

最後の例で 'std :: function'は必要ありません。私は考える:ステートレスラムダは関数ポインタに変換可能です。私。 – MSalters

+0

@MSalters私はそれを試みましたが、VC10とg ++ 4.6.2でコンパイルできませんでした。 '匿名 - 名前空間' :: 'からのパラメータ2を変換できません: 'void(__stdcall * const&)(LPWSTR *)' ' – Praetorian

+0

@MSalters正しいキャプチャのないlambdaは関数ポインタに変換できるので、 'std :: function'は必要ありません。しかし、VC10はこれを実装していません(https://connect.microsoft.com/VisualStudio/feedback/details/572138)。私がg ++で初めて試したときにどうしたのか分かりませんが、間違いなく動作します。 – Praetorian

4

std::functionを使用する必要があると思いますので、私は、一般的なリソース・ガードとしてshared_ptrがもう少し便利。デリータはテンプレート引数の一部である必要はなく、簡単に渡すことができます。カスタムデリータの宣言

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

あなたの答えに感謝します。私は、正しいセマンティックよりも簡単な構文を好むとは思っていません。私の場合、IMHO shared_ptrは適切ではありません。 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

真実、あなたはポインタを回すつもりはありませんが、関連する技術について知っておくと役立つかもしれません。 –

6

decltype()の使用が速くなり、とてもきれいではありません。 std::shared_ptrが代わりですが、std::unique_ptrより大きい値です。ポインタを共有したくない場合は、unique_ptrとしてください。

+1

Visual Studio 2010では、 'std :: unique_ptr 'にする必要があります。そうしないと、ビルドに失敗し、エラーが発生します。 'decltype(:: LocalFree)'は関数ポインタ型ではなく、関数型であるからです。 –

関連する問題