106

有人告诉我,句柄是一种指针,但不是,它允许您保留对对象的引用,而不是对象本身。更详细的解释是什么?

4

8 回答 8

104

句柄可以是任何东西,从整数索引到指向内核空间资源的指针。他们的想法是它们提供了资源的抽象,因此您无需了解资源本身即可使用它。

例如,Win32 API 中的 HWND 是 Window 的句柄。它本身是无用的:你无法从中收集任何信息。但是将它传递给正确的 API 函数,您就可以使用它执行大量不同的技巧。在内部,您可以将 HWND 视为 GUI 窗口表的索引(这可能不一定是它的实现方式,但它使魔法变得有意义)。

编辑:不是 100% 确定你在问题中具体问了什么。这里主要说的是纯C/C++。

于 2009-08-19T23:17:47.750 回答
58

句柄是没有附加可见类型的指针或索引。通常你会看到类似的东西:

 typedef void* HANDLE;
 HANDLE myHandleToSomething = CreateSomething();

因此,在您的代码中,您只需将 HANDLE 作为不透明值传递。

在使用对象的代码中,它将指针转换为真正的结构类型并使用它:

 int doSomething(HANDLE s, int a, int b) {
     Something* something = reinterpret_cast<Something*>(s);
     return something->doit(a, b);
 }

或者将其用作数组/向量的索引:

 int doSomething(HANDLE s, int a, int b) {
     int index = (int)s;
     try {
         Something& something = vecSomething[index];
         return something.doit(a, b);
     } catch (boundscheck& e) {
         throw SomethingException(INVALID_HANDLE);
     }
 }
于 2009-08-19T23:30:35.040 回答
31

句柄一种指针,因为它通常是引用某个实体的一种方式。

更准确地说,指针是一种句柄,但并非所有句柄都是指针。

例如,句柄也可以是内存表的某个索引,它对应于本身包含指向某个对象的指针的条目。

关键是当你有一个“句柄”时,你既不知道也不关心这个句柄实际上是如何识别它所识别的东西的,你只需要知道它确实如此。

还应该清楚的是,对于“到底什么是句柄”没有单一的答案,因为不同事物的句柄,即使在同一个系统中,也可能以不同的方式“在引擎盖下”实现。但是您不必担心这些差异。

于 2009-08-19T23:20:43.783 回答
6

在 C++/CLI 中,句柄是指向位于 GC 堆上的对象的指针。在(非托管)C++ 堆上创建对象是使用实现的,表达式new的结果是“普通”指针。new托管对象使用gcnew表达式在 GC(托管)堆上分配。结果将是一个句柄。您不能对句柄进行指针运算。你不释放手柄。GC 会照顾他们。此外,在程序运行时,GC 可以自由地重新定位托管堆上的对象并更新句柄以指向新位置。

于 2009-08-19T23:17:14.630 回答
5

这出现在Handle-Body-Idiom的上下文中,也称为 Pimpl idiom。它允许通过将实际数据保存到另一个类对象中来保持库的 ABI(二进制接口)相同,该类对象仅由“句柄”对象中的指针引用,该对象由委托给该类的函数组成“身体”。

启用两个对象的恒定时间和异常安全交换也很有用。为此,只需交换指向 body 对象的指针。

于 2009-08-19T23:18:09.793 回答
2

HANDLE hnd;是相同的void * ptr;

HANDLE 是在 Visual Studio (Windows) 的 winnt.h 文件中定义的 typedef:

typedef void *HANDLE;

阅读更多关于手柄

于 2016-01-19T07:08:00.537 回答
2

手柄是您想要的任何东西。

句柄可以是在某些查找表中使用的无符号整数。

句柄可以是指向或指向更大数据集的指针。

这取决于使用句柄的代码的行为方式。这决定了句柄类型。

使用术语“句柄”的原因很重要。这表明它们是对象的标识或访问类型。这意味着,对于程序员来说,它们代表了“钥匙”对某物的访问。

于 2017-09-24T22:27:26.803 回答
0

指针是句柄的一种特殊情况。指针的好处是它直接在内存中标识一个对象,代价是对象变得不可重定位。句柄抽象出对象在内存中的位置,但需要额外的上下文来访问它。例如,将句柄定义为数组索引,我们需要一个数组基指针来计算项目的地址。有时上下文在调用站点是隐含的,例如当对象池是全局的时。这允许优化句柄的大小并使用,例如 16 位 int 而不是 64 位指针。

于 2021-05-27T12:43:10.447 回答