依赖 Windows 句柄的类型作为指针可以吗?

2024-01-25

Windows 句柄有时很烦人,需要记得在之后进行清理(使用创建的笔和画笔执行 GDI 就是一个很好的例子)。 RAII 解决方案很棒,但是为每种不同类型的手柄制作一个完整的(五规则)RAII 类真的那么好吗?当然不是!我能看到的最好的结果是一个完整的通用 RAII 类,其中其他类仅定义应清理句柄时要执行的操作,以及其他特定于句柄的方面。

例如,一个非常简单的模块类可以这样定义(只是一个例子):

struct Module {
    Module() : handle_{nullptr} {}
    Module(HMODULE hm) : handle_{hm, [](HMODULE h){FreeLibrary(h);}} {}
    operator HMODULE() const {return handle_.get();}

private:
    Handle<HMODULE> handle_;
};

这一切都很好,不需要析构函数或任何东西。当然,尽管如此,能够编写Handle不需要析构函数或任何东西的类也很好。为什么不使用现有的 RAII 技术?一个想法是使用一个智能指针来void,但这行不通。以下是正常情况下句柄的实际声明方式:

#define DECLARE_HANDLE(n) typedef struct n##__{int i;}*n
DECLARE_HANDLE(HACCEL);
DECLARE_HANDLE(HBITMAP);
DECLARE_HANDLE(HBRUSH);
...

它实际上区分了句柄类型,这很好,但它使得使用智能指针void不可能的。相反,如果根据定义,句柄是指针,那么可以提取类型怎么办?

我的问题是以下假设是否是一个安全的假设。它使用桌面的句柄,必须将其关闭。除非共享指针和唯一指针之间存在差异(例如,FreeLibrary有它自己的引用计数语义),假设句柄是一个指针并制作一个智能指针来指向它所指向的任何内容,或者我不应该使用智能指针并制作Handle实施 RAII 方面本身?

#include <memory>
#include <type_traits>
#include <utility>
#include <windows.h>

int main() {
    using underlying_type = std::common_type<decltype(*std::declval<HDESK>())>::type;
    std::shared_ptr<underlying_type> ptr{nullptr, [](HDESK desk){CloseDesktop(desk);}};
}

我相信所有 Windows 指针在技术上都是指向系统 Windows 内核部分内部对象的指针(或者有时可能是指向由内核代码分配的用户端对象,或者该主题的某些变体)。

不过,我远不相信你应该将它们视为指针。它们只是纯粹技术角度的指针。它们不再是“指针”,就像 C 风格的“FILE *”不再是指针一样。我不认为你会建议使用shared_ptr<FILE*>以便稍后处理关闭文件。

将句柄包装成稍后清理的东西无论如何都是一个好主意,但我不认为使用智能指针解决方案是正确的解决方案。使用知道如何关闭手柄的模板化系统将是理想的选择。

我想您还需要以某种适用于所有相关人员的好方法来处理“我想将这个句柄从这里传递到其他地方” - 例如你有一个以某种方式获取资源的函数,它返回这些资源的句柄 - 你是否返回一个已经包装的对象,如果是这样,副本是如何工作的?

如果您需要在使用另一个句柄之前保存一个句柄的副本(例如,保存当前笔,然后设置自定义笔,然后恢复),该怎么办?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

依赖 Windows 句柄的类型作为指针可以吗? 的相关文章

随机推荐

  • Android 上有时会忽略 LD_LIBRARY_PATH

    我有一个 Android 应用程序 它会生成许多与我随包分发的库动态链接的本机可执行文件 为了启动这些二进制文件 我使用 LD LIBRARY PATH 环境变量让它们知道从中加载库的位置 但在某些设备上这根本不起作用 LD LIBRARY
  • 如何将无头铬模块与AWS Lambda捆绑在一起?

    我尝试将 Puppeteer 与 Lambda 结合使用 但是 在无服务器部署中 由于超过 250mb 未捆绑包大小限制 Lambda 会出错 因此 为了突破限制 我改用了 Puppeteer 核心 它不包含铬 这需要引用可执行文件的路径来
  • 是否有库或其他方法可以进行 128 位数学运算?

    我正在编写一个加密应用程序 需要使用 128 位整数 除了标准的加 减 乘 除和比较之外 我还需要幂和模函数 有谁知道可以做到这一点的库或其他实现 如果不是 128 位 是否有 64 位选项可用 查看GNU 多精度算术库 http gmpl
  • 如何在react中为状态分配prop值

    我有一个覆盖层 它是从另一个 React 组件启动的 该组件有一个也会自行更改的按钮 当用户单击按钮时 更改就会发生 然后按钮会更改其类名 它还向作为覆盖层的子组件发送一个 prop 值 叠加层会根据属性以及是否单击添加一个类 一切都进展顺
  • 哪个 openid / oauth 库可将 django 项目连接到 Google Apps 帐户?

    我正在为一家使用 Google Apps 登录的公司开发一个 Intranet django 项目 不使用 GAE 所以我希望我的用户能够使用他们的 google 帐户登录来登录我的 django 项目 OpenID 似乎很合适 尽管也许
  • 在ggplot2中自定义“scale_color_gradient2”

    我想在我的图像图中使用我自己的特定颜色 我对 ggplot2 很陌生 所以看了它的手册here http docs ggplot2 org current scale gradient2 html 旧链接不存在 现在是here https
  • TFS 2005下永久删除

    如何永久删除 TFS 2005 源代码管理下的文件夹 文件 我知道关于tf destroy命令 但这仅适用于 TFS 2008 我也知道关于CodePlex 上的 TFS PowerPack http tfspowerpack codepl
  • 用于验证 Active Directory 对象 SID 的正则表达式

    我正在寻找一种方法来验证从 Active Directory 插入的对象 SID 是否有效 是否可以使用preg match or preg match all 我在网上查找了用于此验证的正则表达式 但我找不到任何东西 Example si
  • Swift UIAlertController,文本中带有 url

    我有这个代码 func alertBox txt String let ac UIAlertController title MyTtle message More information in my website preferredSt
  • Select2 占位符问题

    我有一个 Select2 多选 html 元素 渲染时不显示占位符 但如果我选择并删除该项目 则会显示占位符 我不知道如何让它发挥作用 请指教 最初 选择时 移除物品后 Code Html DropDownListFor m gt m Ve
  • sizeof(array) 在运行时如何工作?

    我读过 C 中的 sizeof 运算符是在编译时解释的 并且由于在编译时编译器知道数组大小及其类型 因此 sizeof 能够计算数组占用的字节数 但是 sizeof 如何适用于以下代码 include
  • 在 SQL 中聚合

    我有一个看起来像这样的表 Conversion Date User Name Last Date Touch Touch Count 7 15 2017 A 6 17 2017 1 7 16 2017 B 6 24 2017 2 7 19
  • GCDAsyncSocket 服务器仅在第一次接收数据

    每次当我按下发送按钮时客户端都会发送消息 但服务器仅在第一次接收消息 服务器有什么问题 Server void viewDidLoad super viewDidLoad asyncSocket GCDAsyncSocket alloc i
  • AngularJS 在工厂和控制器之间跨模块共享数据

    我有一个 angularjs 应用程序 它有几个模块 主要模块如下所示 var app angular module mainMod apiService app controller MainCtrl function Socket sc
  • 如何使用 Terraform 的文件配置程序从本地计算机复制到虚拟机?

    我是 Terraform 的新手 到目前为止 我已成功在 Azure 上启动并运行了基本的 VM 加上资源管理器修剪 我想到的下一个任务是让 Terraform 将文件从本地计算机复制到新创建的实例中 理想情况下 我正在寻找一种解决方案 每
  • 无法连接到 localhost/127.0.0.1 android

    我是 android 开发的新手 并尝试通过改造库调用 android 中的本地 NET Web api 服务 在 IIS 上启动我的 Web api 后 我收到此错误无法连接到 localhost 127 0 0 1 android 当我
  • 使用 JavaScript 获取用户代理

    我想要一个可以获取用户的用户代理并将其支持到属性的脚本 我正在制作网站问题联系表 我通常需要知道用户使用的浏览器 如何检测用户代理字符串并将其支持为输入元素的值 我的 html 看起来像这样
  • 混合运行时是可行的解决方案吗?

    在我的公司 我们最近从 VC9 切换到 VC10 我们迁移了我们的项目 但是负责人告诉我们 我们必须在我们的生产机器上保留一些用 VC9 编译的基本通用 DLL 一段时间 这些 DLL 使用自定义结构 其中一些包含std vector st
  • 在 C++ 的条件或控制语句中声明和初始化变量

    在斯特鲁斯特鲁普的C 编程语言 特别版 第 3 版 Stroustrup 写道 在控制语句的条件中声明和初始化变量不仅是允许的 而且是鼓励的 他写道 他鼓励这样做 因为它将变量的范围缩小到仅需要它们的范围 所以像这样的事情 if int i
  • 依赖 Windows 句柄的类型作为指针可以吗?

    Windows 句柄有时很烦人 需要记得在之后进行清理 使用创建的笔和画笔执行 GDI 就是一个很好的例子 RAII 解决方案很棒 但是为每种不同类型的手柄制作一个完整的 五规则 RAII 类真的那么好吗 当然不是 我能看到的最好的结果是一