c – 使用shared_ptr与自定义删除器进行HANDLE RAII兼容

我最近在 SO发布了关于RAII的一般问题.
但是,我的HANDLE示例仍然有一些实现问题.

在Windows.h中,一个HANDLE被打破为void *.因此,需要正确的shared_ptr定义

std::tr1::shared_ptr<void> myHandle (INVALID_HANDLE_VALUE,CloseHandle);

示例1 Createtoolhelp32Snapshot:返回HANDLE并工作.

const std::tr1::shared_ptr<void> h
    (Createtoolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL),CloseHandle);

当我在定义中使用void(什么是正确的方式?)问题继续,当我尝试使用这个指针调用一些更多的winapi命令.他们在功能上工作,但是很丑,我确信必须有更好的解决方案.

在以下示例中,h是通过顶部定义创建的指针.

示例2 OpenProcesstoken:最后一个参数是PHANDLE.中等丑与演员.

OpenProcesstoken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,(PHANDLE)&h);

示例3 Process32First:第一个参数是一个HANDLE.真的很丑

Process32First(*((PHANDLE)&h),&pEntry);

示例4简单的比较一个恒定的HANDLE.真的很丑

if (*((PHANDLE)&h) == INVALID_HANDLE) { /* do something */ }

为HANDLE创建适当的shared_ptr的正确方法是什么?

解决方法

示例1可以

示例2是错误的.通过盲目投射到PHANDLE,shared_ptr逻辑被绕过.它应该是这样的:

HANDLE h;
OpenProcesstoken(....,&h);
shared_ptr<void> safe_h(h,&::CloseHandle);

或者分配给一个pre-exising shared_ptr:

shared_ptr<void> safe_h = ....
{
  HANDLE h;
  OpenProcesstoken(....,&h);
  safe_h.reset(h,&::CloseHandle);
}//For extra safety,limit visibility of the naked handle

或创建自己的安全版本的OpenProcesstoken,返回一个共享句柄,而不是使用PHANDLE:

// Using SharedHandle defined at the end of this post
SharedHandle OpenProcess(....)
{
    HANDLE h = INVALID_HANDLE_VALUE;
    ::OpenProcesstoken(....,&h);
    return SharedHandle(h);
}

示例3:不需要走这些弯路.这应该是可以的

Process32First(h.get(),...);

示例4:再次,没有绕道:

if (h.get() == INVALID_HANDLE){...}

为了使事情更美好,你可以打字像:

typedef shared_ptr<void> SharedHandle;

或者更好的是,如果要使用CloseHandle()关闭所有句柄,请创建一个包装shared_ptr并自动提供正确的删除器的SharedHandle类:

// Warning: Not tested. For illustration purposes only
class SharedHandle
{
public:
  explicit SharedHandle(HANDLE h) : m_Handle(h,&::CloseHandle){};
  HANDLE get()const{return m_Handle.get();}

  //Expose other shared_ptr-like methods as needed
  //...

private:
  shared_ptr<void> m_Handle;
};

相关文章

对象的传值与返回说起函数,就不免要谈谈函数的参数和返回值...
从实现装饰者模式中思考C++指针和引用的选择最近在看...
关于vtordisp知多少?我相信不少人看到这篇文章,多半是来自...
那些陌生的C++关键字学过程序语言的人相信对关键字并...
命令行下的树形打印最近在处理代码分析问题时,需要将代码的...
虚函数与虚继承寻踪封装、继承、多态是面向对象语言的三大特...