std::unique_ptr,为win32 LocalFree自定义删除器。

问题描述 投票:17回答:4

我有win32的API CommandLineToArgvW 其中返回一个 LPWSTR* 并警告我说

CommandLineToArgvW 为指向参数字符串的指针和参数字符串本身分配一个连续的内存块;当参数列表不再需要时,调用应用程序必须释放参数列表使用的内存。要释放内存,请使用一个对 LocalFree 功能。

http:/msdn.microsoft.comen-uslibrarywindowsdesktopbb776391(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;
}

上面的代码有什么问题吗?

c++ winapi memory-management c++11 unique-ptr
4个回答
10
投票

在我看来是正确的。你可以把它弄得更简洁一些,通过指定的 unique_ptr的 deleter inline,而不是为它创建一个漏斗。

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版本。 在这个答案第一次写的时候,VS2010是发布的VS版本。它 不支持 将无捕获的lambdas转换为函数指针,所以你必须使用 std::function 在第二个例子中

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

6
投票

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

5
投票

我发现 shared_ptr 作为一个通用的资源保护器,它更有用一些。它不要求deleter是模板参数的一部分,因此可以很容易地传递。

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

0
投票

那么使用 微软视窗执行库(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;
}
© www.soinside.com 2019 - 2024. All rights reserved.