是否有适用于“手柄”的适当“所有权在一个包中”?

Posted

技术标签:

【中文标题】是否有适用于“手柄”的适当“所有权在一个包中”?【英文标题】:Is there a proper 'ownership-in-a-package' for 'handles' available? 【发布时间】:2013-02-14 15:22:02 【问题描述】:

Handles 具有除指针之外的适当语义。所以对我来说一个这样的例子(摘自Rule of Zero):

class module 
public:
    explicit module(std::wstring const& name)
    : handle  ::LoadLibrary(name.c_str()), &::FreeLibrary  

    // other module related functions go here

private:
    using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;

    module_handle handle;
;

使用unique_ptr 作为句柄的“包中所有权”是一个不好的例子。首先,它利用句柄是指针类型的内部知识,并使用它为“不透明”句柄类型构建的基本类型创建unique_ptr

句柄可以是任何类型,它们可能是指针,可能是索引或谁知道。最重要的是,您手头(例如大多数 C API)是一个句柄及其资源释放函数。

在句柄语义中工作是否存在适当的“包中所有权”?我的意思是,已经公开供一个人使用?

对我来说,unique_ptr 等。人。不起作用,我必须对句柄类型做出不必要的假设,而我想要的只是通过不透明的句柄类型及其释放获得“包中的所有权”功能,单独。

查看句柄类型内部以根据此信息进行构造是没有意义的。是把手,应该没关系。

我在这里引用另一个SO用户another question'sanswer的感受:

创建一个特定的“智能指针”类,不会花很长时间。不要滥用 图书馆类。句柄语义与 C++ 指针;一方面,取消引用 HANDLE 是没有意义的。

使用自定义智能句柄类的另一个原因 - NULL 不 总是意味着一个空的句柄。有时是 INVALID_HANDLE_VALUE, 这不一样。

免责声明:

这个问题重新表述并建立在这个问题的基础上:

Where's the proper (resource handling) Rule of Zero?

【问题讨论】:

我不同意你的前提。 unique_ptr 可能有点用词不当——它处理资源HANDLE 也处理资源。这是一个完美的匹配。 我的前提不仅仅基于类型名称... 您的问题到底是什么?你不喜欢unique_ptr这个名字? @EtiennedeMartel:要将unique_ptr 用于非指针句柄,您需要一个特殊的删除器来定义嵌套的pointer 类型,而pointer 类型不能简单地是,比如说int,因为int 不符合unique_ptr 想要的NullablePointer 要求。但是,you can write a simple wrapper 使 anything 适应那些可空指针要求。如果您愿意,还可以添加一个转发到*value 的一元operator* 和一个operator-&gt;,这样您就可以实际使用*upup-&gt;foo() @Xeo:如果您要编写该包装器的麻烦...为什么不编写一个可以保存任何值并在其上调用给定函数/函子的适当 RAII 对象销毁时键入?这比使用unique_ptr 来处理非指针的事情要简单得多。说真的,为一个对象编写复制/移动构造函数并不是一个繁重的负担。 【参考方案1】:

unique_ptr 类型不如短语“handle”通用,是的。但为什么不应该呢?您的“处理”示例之一(例如,整数索引)与unique_ptr 一样通用。您无法将一种特定类型的句柄与“所有句柄”进行比较。

如果你想要一个单一的、具体的 C++ 类型(或类型模板),它是一个句柄,但实际上没有定义任何特定的处理语义,那么......我帮不了你。我认为没有人能轻松应对。

【讨论】:

它不太通用,因此应该在合适的地方使用。当人们开始查找HANDLE(假定是不透明的,手柄的主要特征之一)的基础,并在不太通用的工具中使用该信息时,对我来说,这是难闻的气味。当然,对于我来说,可以断言HANDLEvoid *,那么其他基于句柄的库呢,你会假设断言消失了吗?而且这个假设不是句柄语义的一部分,HANDLE 不透明的。 @chico:“其他基于句柄的库”有不同的句柄类型。 unique_ptrone 句柄类型。您在编码中遇到了什么实际问题? unique_ptr 是一种句柄类型吗?我不明白你的意思。 HANDLE 句柄 类型。我的实际问题是忽略它是不透明的 来利用unique_ptr 来管理它所引用的资源的生命周期。我认为这是一种不好的做法,并且我要求一种已知的“所有权在一个包中”的替代方案,它是正确的。我的意思是,不是那样的违规封装。 句柄类型是不透明的,一个好的工具会处理句柄,最后是整数和基于指针的,同样的语法方式。 @chico:你一直说句柄类型必须是不透明的,但我看不出有任何理由。 unique_ptr 非常适合具有指针语义的句柄。当然,它没有非指针语义。这是一种的句柄。 句柄是否被假定为不透明并不重要,重要的是它们通常被假定为不透明。您可以在内部将您的句柄类型构建为void *,并为您的客户预先声明它将是这样的。您的客户可以安全地使用unique_ptr&lt;void&gt;(看起来unique_ptr&lt;void&gt; 并没有什么意义,您无法从句柄类型推断任何内容,它不是指向无类型的指针)。但这是您的特殊手柄的情况。一般而言,此过程不适用于句柄。【参考方案2】:

std::experimental::unique_resource

【讨论】:

为什么要强制客户端在使用位置手动提供清理(即传递给make_scoped_resource的lambda)? @R.MartinhoFernandes 不是unique_ptrdeleter 的情况吗?如果在句柄语义中使用 default_deleter 是否有意义?我想在大多数情况下,你会得到更短的语法,并且你有 std::unique_resource 选项不会强制这样做。但是,我仍然想知道一个好的解决方案。 如果您的删除器是默认可构造的,则不会。关键是 make_scoped_resource,就像 unique_ptr 的带有删除器的 ctor 一样,永远不应该在客户端代码中使用。它应该只在库函数中使用。像make_gl_list 这样的东西,内部可能使用make_scoped_resource,但不会强迫客户关心它。 @R.MartinhoFernandes 为什么要强制语言用户将所有涉及遗留 API 使用句柄的情况封装起来?库函数可能需要为某些操作调用一次遗留 API,为什么要在这种微不足道的情况下强制包装?这是与 C 交互的人的常见用法,为什么不提供好的资源来处理这个问题呢?小包装器,私有的类似功能的包装器库,代码技巧,这一切都必须去! 什么。在您的代码示例中,用户本身必须 处理遗留 API(请参阅那里对 glDeleteLists 的调用?)。那是应该消失的。

以上是关于是否有适用于“手柄”的适当“所有权在一个包中”?的主要内容,如果未能解决你的问题,请参考以下文章

是否有适用于 iPhone 应用程序的非采样时间分析工具?

以编程方式检测 SwiftUI 中的暗模式以显示适当的图像

编写适用于 MVC 和 Web API 请求的过滤器

HTA 游戏手柄 API(或替代方案)

是否可以在pyqtgraph中调整句柄的大小?

请求生命周期: