C++ 什么是句柄?为什么会有句柄?HANDLE

本文详细解释了Windows系统中句柄的概念及其作用,句柄作为32位无符号整数,用于间接引用内核对象,如文件、线程、进程等。文章还探讨了句柄表的工作原理以及进程ID和HINSTANCE的含义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

出处:http://www.cppblog.com/mymsdn/archive/2009/02/19/handle-in-windows.html

从广义上,能够从一个数值拎起一大堆数据的东西都可以叫做句柄。句柄的英文是"Handle",本义就是"柄",只是在计算机科学中,被特别地翻译成"句柄",其实还是个"柄"。从一个小东西拎起一大堆东西,这难道不像是个"柄"吗?

然后,指针其实也是一种"句柄",只是由于指针同时拥有更特殊的含义——实实在在地对应内存里地一个地址——所以,通常不把指针说成是"句柄"。但指针也有着能从一个32位的值引用到一大堆数据的作用,这不是句柄又是什么?

Windows系统中有许多内核对象(这里的对象不完全等价于"面向对象程序设计"一词中的"对象",虽然实质上还真差不多),比如打开的文件,创建的线程,程序的窗口,等等。这些重要的对象肯定不是4个字节或者8个字节足以完全描述的,他们拥有大量的属性。为了保存这样一个"对象"的状态,往往需要上百甚至上千字节的内存空间,那么怎么在程序间或程序内部的子过程(函数)之间传递这些数据呢?拖着这成百上千的字节拷贝来拷贝去吗?显然会浪费效率。那么怎么办?当然传递这些对象的首地址是一个办法,但这至少有两个缺点:

  1. 暴露了内核对象本身,使得程序(而不是操作系统内核)也可以任意地修改对象地内部状态(首地址都知道了,还有什么不能改的?),这显然是操作系统内核所不允许的;
  2. 操作系统有定期整理内存的责任,如果一些内存整理过一次后,对象被搬走了怎么办?

所以,Windows操作系统就采用进一步的间接:在进程的地址空间中设一张表,表里头专门保存一些编号和由这个编号对应一个地址,而由那个地址去引用实际的对象,这个编号跟那个地址在数值上没有任何规律性的联系,纯粹是个映射而已。

在Windows系统中,这个编号就叫做"句柄"。

 

Handle在Windows中的含义很广泛,以下关于谈到的Handle除非特别说明,将仅限于进程、线程的上下文中。

1、先来谈谈Handle

Handle本身是一个32位的无符号整数,它用来代表一个内核对象。它并不指向实际的内核对象,用户模式下的程序永远不可能获得一个内核对象的实际地址(一般情况下)。那么Handle的意义何在?它实际上是作为一个索引在一个表中查找对应的内核对象的实际地址。那么这个表在哪里呢?每个进程都有这样的一个表,叫句柄表。该表的第一项就是进程自己的句柄,这也是为什么你调用GetCurrentProcess()总是返回0x7FFFFFFF原因。

简单地说,Handle就是一种用来"间接"代表一个内核对象的整数值。你可以在程序中使用handle来代表你想要操作的内核对象。这里的内核对象包括:事件(Event)、线程、进程、Mutex等等。我们最常见的就是文件句柄(file handle)。

另外要注意的是,Handle仅在其所属的进程中才有意义。将一个进程拥有的handle传给另一个进程没有任何意义,如果非要这么做,则需要使用DuplicateHandle(),在多个进程间传递Handle是另外一个话题了,与这里要讨论的无关。

2、进程ID

首先,进程ID是一个32位无符号整数,每个进程都有这样的一个ID,并且该ID在系统范围内是唯一的。系统使用该ID来唯一确定一个进程。

深入些说,系统可能使用进程ID来计算代表该进程的内核对象的基地址(及EPROCESS结构的基地址),具体的计算公式你可以去问微软的OS开发人员。

3、HINSTANCE

HINSTANCE也是一个32无符号整数,它表示程序加载到内存中的基地址。

### C++句柄的概念、定义与用法 #### 什么是句柄? 在 C++ 编程中,句柄通常被理解为一种间接访问资源的方式。具体来说,句柄是一个指向某个对象或资源的引用机制[^4]。它可以表示文件、窗口、设备上下文或其他系统资源的对象。通过句柄,程序可以操作这些底层资源而无需直接管理其复杂细节。 #### 句柄的作用 句柄的主要作用是简化对复杂数据结构的操作,并提供抽象层以便于管理和维护资源。例如,在 Windows 系统中,许多 API 函数会返回一个句柄作为结果,用于后续对该特定资源的操作。如果未正确关闭句柄,则可能导致资源泄漏等问题。 #### C++句柄的具体实现方式 C++句柄可以通过多种方式进行设计和实现,其中较为常见的有以下几种: 1. **智能指针模式下的句柄** 使用智能指针(如 `std::shared_ptr` 或自定义封装)来构建句柄类是一种现代做法。这种方式不仅提供了自动内存管理功能,还支持引用计数等特性。 下面展示了一个简单的句柄类示例: ```cpp class Base { public: virtual ~Base() {} virtual void use() const = 0; virtual int compute() const = 0; }; template<typename T> class Handle { private: T* ptr; public: explicit Handle(T* t) : ptr(t) {} ~Handle() { delete ptr; } T& operator*() const { return *ptr; } T* operator->() const { return ptr; } }; ``` 2. **基于引用计数的句柄** 这种类型的句柄类似于 COM 对象中的引用计数模型。每当复制一份句柄时,都会增加引用计数;当销毁某份副本时则减少引用计数。一旦引用计数降为零,就会释放关联的实际对象及其占用的资源。 如下所示的是一个典型的引用计数型句柄的设计片段: ```cpp struct Item_base {}; class Handle_item { private: Item_base* p; std::size_t* cnt; public: Handle_item(const Item_base& item) : p(item.clone()), cnt(new std::size_t(1)) {} Handle_item(const Handle_item& h) : p(h.p), cnt(h.cnt) { ++(*cnt); } ~Handle_item() { if (--(*cnt) == 0) { delete p; delete cnt; } } Handle_item& operator=(const Handle_item&); }; ``` 3. **实际应用案例——多态场景下的句柄运用** 结合虚函数表机制,可以在运行期动态决定调用哪个派生类成员函数版本。这使得即使基类指针也能安全地执行子类特化行为。 示例代码如下: ```cpp #include <iostream> using namespace std; class Base { protected: int data; string name; public: Base(int d, string n) : data(d), name(n) {} virtual void use() const { cout << "Using base object named: " << name << endl; } virtual int compute() const { return data * 2; } virtual ~Base() {} }; class Derived : public Base { public: Derived(int d, string n, double factor) : Base(d, n), fact(factor) {} void use() const override { cout << "Using derived object with factor: " << fact << ", Name: " << this->name << endl; } int compute() const override { return static_cast<int>(this->data * fact); } private: double fact; }; int main() { Handle<Base> h1(new Base(2, "Base")); h1.use(); cout << "Base compute:" << (*h1).compute() << endl; Handle<Derived> h2(new Derived(3, "derived", 3)); h2.use(); cout << "Derived compute:" << (*h2).compute() << endl; return 0; } ``` 上述例子展示了如何利用模板参数化的句柄类处理不同类型的继承关系实例[^2]。 #### 常见注意事项 - 需要注意防止循环依赖导致无法正常回收资源的情况发生。 - 如果涉及跨模块传递句柄,请确保接收方具备足够的权限去解构原始对象。 - 正确初始化和清理句柄所持有的资源非常重要,否则容易引起各种难以追踪的问题,比如野指针错误或者双重删除异常等等[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值