发布时间:2026-09-28 17:13:01 浏览次数:1
在C++中,句柄类是一种将资源管理委托给类实例的方法,以确保正确地释放使用的资源。本篇文章将详细讲解什么是C++句柄类,并展示了如何创建和使用句柄类。
句柄类是一种 C++ 类,主要用于管理资源,通过封装对资源的访问来确保资源有效使用。句柄类通常用于管理底层的操作系统资源,例如文件、网络套接字、设备上下文、数据库连接等。在释放资源时,句柄类将确保资源正确释放,以避免资源泄漏。
在使用句柄类时,通常需要创建一个句柄对象,该对象控制外部资源的分配和释放。外部资源的句柄被储存在句柄对象中,并在对象销毁时释放。在访问外部资源时,需要通过公开的接口来获取该资源。
句柄类的创建包括以下步骤:
定义用于包含句柄的类,该类应该有至少一个构造函数和一个析构函数。
class Handle{public: Handle() : m_handle(nullptr) {} virtual ~Handle() {}private: HANDLE m_handle;};定义句柄访问接口。该接口应该提供异步关闭句柄和同步关闭句柄的方法。
class Handle{public: Handle() : m_handle(nullptr) {} virtual ~Handle() {} virtual void Close() = 0; virtual bool IsValid() = 0;private: HANDLE m_handle;};实现一个句柄类,该类应该实现句柄访问接口。该类应该保存在当前应用程序上下文并保存对外部资源的访问。在析构函数中,应使用访问接口中定义的 Close 方法来释放外部资源。
例如,在Windows操作系统中,创建一个控制台屏幕缓冲区的句柄类可以采用以下步骤:
class ConsoleHandle : public Handle{public: ConsoleHandle() : Handle() { m_handle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CONSOLE_TEXTMODE_BUFFER, nullptr); } virtual void Close() override { if (m_handle != nullptr) { CloseHandle(m_handle); m_handle = nullptr; } } virtual bool IsValid() override { return m_handle != nullptr && m_handle != INVALID_HANDLE_VALUE; }private: HANDLE m_handle;};auto console = std::make_unique<ConsoleHandle>();if (!console->IsValid()){ std::cerr << "Unable to create console handle!" << std::endl; return -1;}句柄类用于管理资源,以确保正确地释放使用的资源。句柄类的使用流程如下:
创建句柄类的实例。
auto console = std::make_unique<ConsoleHandle>();if (!console->IsValid()){ std::cerr << "Unable to create console handle!" << std::endl; return -1;}通过访问句柄,对资源进行读写操作。
例如,在Windows操作系统中,使用句柄类实例来读取和写入屏幕缓冲区:
DWORD bytesWritten;WriteConsoleOutputCharacter( console->GetPosition(), "Hello, World!", strlen("Hello, World!"), { 0, 0 }, &bytesWritten);DWORD bytesRead;CHAR_INFO readBuffer[80]; ReadConsoleOutput( console->GetPosition(), readBuffer, { 80, 1 }, { 0, 0 }, &consoleRect);在使用句柄完成操作后,释放该句柄。
console->Close();对于控制台缓冲区的句柄,目前只使用了CreateConsoleScreenBuffer() 创建时返回的句柄。这个句柄的生命周期主要在应用程序运行期间,并随着句柄类的销毁被关闭。
但是,有一些资源,如数据库连接池,不应该每次使用创建和销毁,因为创建和销毁连接池可能非常昂贵。在这种情况下,应当维护连接池并在使用结束后将其返回到池中,以便复用。下面提供一个简单的数据库连接池的句柄示例:
class DbConnectionHandle : public Handle{public: DbConnectionHandle(std::unique_ptr<DbConnection> connection, std::shared_ptr<DbConnectionPool> pool) : Handle() { m_connection = std::move(connection); m_pool = pool; } virtual ~DbConnectionHandle() { if (m_connection != nullptr) { m_pool->ReturnConnection(std::move(m_connection)); } } virtual bool IsValid() override { return m_connection != nullptr && m_connection->IsOpen(); } DbConnection* GetConnection() { return m_connection.get(); }private: std::unique_ptr<DbConnection> m_connection; std::shared_ptr<DbConnectionPool> m_pool;};该示例在创建类时将其初始化为一个指向已经分配给该连接池的连接的封装,并在销毁对象时将连接返回到连接池中。为了保持高效,此示例使用了std::unique_ptr和std::shared_ptr来防止了句柄和连接泄漏。
完整的示例程序见这里。
本篇文章简要介绍了C++句柄类的概念和实现方法,并通过控制台缓冲区句柄和数据库连接池句柄示例带领读者完成了句柄类的设计和使用。通过句柄类,我们可以有效的管理内存、数据库连接以及诸如系统文件句柄等资源,同时可以减轻开发人员的工作量,并避免产生错误和资源泄漏。