std :: unique_ptr,带有win32 LocalFree的自定义删除器

时间:2012-03-27 15:51:49

标签: c++ winapi memory-management c++11 unique-ptr

我有win32 API CommandLineToArgvW,它返回LPWSTR*和 警告我

  

CommandLineToArgvW为其分配一块连续的内存   指向参数字符串的指针,以及参数字符串   他们自己;调用应用程序必须释放使用的内存   不再需要时的参数列表。要释放内存,请使用   单次调用LocalFree函数。

请参阅 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 个答案:

答案 0 :(得分:10)

对我而言看起来是正确的。你可以通过指定unique_ptr的删除内联而不是为它创建一个仿函数来使它更简洁。

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

或者,如果您不想弄乱LocalFree的签名和调用约定,可以使用lambda进行删除。

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

注意:在第一次写这个答案时,VS2010是已发布的VS版本。它将无捕获的lambda转换为doesn't support到函数指针,因此你必须在第二个例子中使用std::function

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

答案 1 :(得分:6)

自定义删除器的声明并不是那么漂亮,使用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 );

答案 2 :(得分:5)

我认为shared_ptr作为通用资源保护更有用。它不需要删除器作为模板参数的一部分,因此可以很容易地传递。

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

答案 3 :(得分:0)

那使用Microsoft Windows Implementation Libraries (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;
}