有人告诉我,句柄是一种指针,但不是,它允许您保留对对象的引用,而不是对象本身。更详细的解释是什么?
8 回答
句柄可以是任何东西,从整数索引到指向内核空间资源的指针。他们的想法是它们提供了资源的抽象,因此您无需了解资源本身即可使用它。
例如,Win32 API 中的 HWND 是 Window 的句柄。它本身是无用的:你无法从中收集任何信息。但是将它传递给正确的 API 函数,您就可以使用它执行大量不同的技巧。在内部,您可以将 HWND 视为 GUI 窗口表的索引(这可能不一定是它的实现方式,但它使魔法变得有意义)。
编辑:不是 100% 确定你在问题中具体问了什么。这里主要说的是纯C/C++。
句柄是没有附加可见类型的指针或索引。通常你会看到类似的东西:
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);
}
}
句柄是一种指针,因为它通常是引用某个实体的一种方式。
更准确地说,指针是一种句柄,但并非所有句柄都是指针。
例如,句柄也可以是内存表的某个索引,它对应于本身包含指向某个对象的指针的条目。
关键是当你有一个“句柄”时,你既不知道也不关心这个句柄实际上是如何识别它所识别的东西的,你只需要知道它确实如此。
还应该清楚的是,对于“到底什么是句柄”没有单一的答案,因为不同事物的句柄,即使在同一个系统中,也可能以不同的方式“在引擎盖下”实现。但是您不必担心这些差异。
在 C++/CLI 中,句柄是指向位于 GC 堆上的对象的指针。在(非托管)C++ 堆上创建对象是使用实现的,表达式new
的结果是“普通”指针。new
托管对象使用gcnew
表达式在 GC(托管)堆上分配。结果将是一个句柄。您不能对句柄进行指针运算。你不释放手柄。GC 会照顾他们。此外,在程序运行时,GC 可以自由地重新定位托管堆上的对象并更新句柄以指向新位置。
这出现在Handle-Body-Idiom的上下文中,也称为 Pimpl idiom。它允许通过将实际数据保存到另一个类对象中来保持库的 ABI(二进制接口)相同,该类对象仅由“句柄”对象中的指针引用,该对象由委托给该类的函数组成“身体”。
启用两个对象的恒定时间和异常安全交换也很有用。为此,只需交换指向 body 对象的指针。
HANDLE hnd;
是相同的void * ptr;
HANDLE 是在 Visual Studio (Windows) 的 winnt.h 文件中定义的 typedef:
typedef void *HANDLE;
阅读更多关于手柄
手柄是您想要的任何东西。
句柄可以是在某些查找表中使用的无符号整数。
句柄可以是指向或指向更大数据集的指针。
这取决于使用句柄的代码的行为方式。这决定了句柄类型。
使用术语“句柄”的原因很重要。这表明它们是对象的标识或访问类型。这意味着,对于程序员来说,它们代表了“钥匙”或对某物的访问。
指针是句柄的一种特殊情况。指针的好处是它直接在内存中标识一个对象,代价是对象变得不可重定位。句柄抽象出对象在内存中的位置,但需要额外的上下文来访问它。例如,将句柄定义为数组索引,我们需要一个数组基指针来计算项目的地址。有时上下文在调用站点是隐含的,例如当对象池是全局的时。这允许优化句柄的大小并使用,例如 16 位 int 而不是 64 位指针。