18

私はwin32APIを持っていますCommandLineToArgvW。これは、を返し、LPWSTR*警告します。

CommandLineToArgvW引数文字列へのポインタと引数文字列自体に連続したメモリのブロックを割り当てます。呼び出し元のアプリケーションは、引数リストが不要になったときに、引数リストで使用されていたメモリを解放する必要があります。メモリを解放するには、LocalFree関数を1回呼び出します。

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

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

私はstd::unique_ptrカスタムデリッターを使って考えていました、そのようなもの:

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

上記のコードに問題はありますか?

4

4 に答える 4

11

それは私には正しいように見えます。unique_ptrファンクターを作成するのではなく、's deleterをインラインで指定することで、もう少し簡潔にすることができます。

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バージョンでした。キャプチャレスラムダから関数ポインタへの変換はサポートされていないためstd::function、2番目の例で使用する必要があります

std::unique_ptr<LPWSTR, std::function<void(LPWSTR *)>> 
      p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ), 
         [](LPWSTR *ptr){ ::LocalFree( ptr ); } );
于 2012-03-27T16:09:23.533 に答える
7

カスタム削除機能の宣言はそれほどきれいではなく、使用するdecltype()方が高速です。std::shared_ptrは代替手段ですが、よりも大きくなりstd::unique_ptrます。ポインタを共有したくない場合は、を取りますunique_ptr

std::unique_ptr<LPWSTR, decltype(::LocalFree)> 
     p( ::CommandLineToArgvW( L"cmd.exe p1 p2 p3", &n ), ::LocalFree );
于 2013-02-25T12:56:44.450 に答える
5

shared_ptr一般的なリソースガードとしてもう少し便利だと思います。削除ツールがテンプレート引数の一部である必要はないため、簡単に渡すことができます。

std::shared_ptr<LPWSTR> p(
    ::CommandLineToArgvW(L"cmd.exe p1 p2 p3", &n),
    ::LocalFree);
于 2012-04-01T08:30:00.053 に答える
0

そして、 Microsoft Windows実装ライブラリ(WIL)を使用した回答はどうですか?

まず、WILを(端末から)「インストール」します。

c:\dev>git clone https://github.com/microsoft/wil.git

その後:

#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;
}
于 2020-04-23T13:50:53.150 に答える