Windows HANDLE RAII 管理,如果返回布尔值而不是句柄怎么办?
Windows HANDLE RAII management, what if a bool is returned instead of a handle?
以前:
正确关闭WinAPI句柄(避免重复关闭)
我的问题是:如果 CreateFile 返回一个布尔值而不是一个句柄,并且输出有一个指针怎么办?发明的例子:
HANDLE handle;
if (CreateFile(&handle, "filename", ...) == true) {
//...
}
有没有很好的语法可以在C++提供的 RAII 类使用它?这样我就可以把我的对象作为第一个参数而不是指针。
在这种情况下,我只需向 RAII 类添加一个覆盖operator&
,例如:
template< class traits >
class HandleWrapper {
...
public:
...
traits::HandleType* operator&() { return &FHandle; }
};
然后像这样使用它:
HandleWrapper<KernelHandleTraits> handle;
if (CreateFile(&handle, "filename", ...) == true) {
...
}
正如其他人所提到的,您当然可以通过重载operator&
来实现目标,但这充满了风险,首先破坏了使用包装器的目的。
考虑如何使用假设的 HandleWrapper,其中包含简单的重载operator&
,该重载仅返回指向内部句柄的指针:
HandleWrapper<KernelHandleTraits> handle;
if (CreateFile(&handle, "first", ...) == true) {
// process the first file...
}
if (CreateFile(&handle, "second", ...) == true) {
// process the second file...
}
这会将句柄泄漏到第一个文件,因为operator&
重载允许您执行后门分配。 请注意,包装类没有专门赋值运算符,因此它不必在完成第一个资源后重用包装器来跟踪第二个资源的复杂性。
如果包装器已经包含资源,您可以扩展包装器以执行更智能的操作,但类变得更加复杂,并且您离 RAII 的想法越来越远。
如果我们拆分头发,引用的 HandleWrapper 代码应用 RRID(资源释放是销毁)而不是 RAII(资源分配是初始化)。
- RRID 类是一个包装器,您可以将已分配资源的所有权转移到其中(以确保稍后释放它)。
- RAII 类的生存期与其包装的资源完全相同。 它在资源存在的那一刻就拥有资源,并在资源释放时死亡。
如果您有一个将资源作为"输出参数"返回的函数,则可以编写适配器函数:
HANDLE CreateFileAdapter(const char * filename, ...) {
HANDLE handle;
return CreateFile(&handle, "filename", ...) ? handle : INVALID_HANDLE_VALUE;
}
然后,您可以通过调用适配器函数按原样使用 HandleWrapper:
HandleWrapper<KernelHandleTraits> handle(CreateFileAdapter("filename", ...));
严格的 RAII 解决方案会将资源的分配封装在构造函数中,就像将释放封装在其析构函数中一样。 您可以在 RRID 包装器和适配器函数的背面构建 RAII 包装器:
class FileHandleWrapper : public HandleWrapper<KernelHandleTraits> {
public:
FileHandleWrapper(const char * file_name, ...) :
HandleWrapper(CreateFileAdapter(file_name, ...) {}
private:
static HANDLE CreateFileAdapter(const char *file_name, ...) {
HANDLE handle;
return CreateFile(&handle, "filename", ...) ?
handle : INVALID_HANDLE_VALUE;
}
};
请注意,我已将适配器函数设置为私有静态函数,以确保没有人以不安全的方式使用它。
你想要的,是一个调用CreateFile
的函数,如果它返回false,则抛出,并返回句柄。 像这样:
HANDLE createFileOrThrow(const std::string& filename, ... )
{
HANDLE handle;
if (!CreateFile(&handle, filename.c_str(), ...) {
throw suitable_exception_type();
}
return handle;
}
HandleWrapper<KernelHandleTraits> hFile(CreateFileOrThrow("filename"));
在这个特定示例中,您可以将函数设置为立即调用的 lambda,但您可能希望经常执行此操作。
或者:
HandleWrapper<KernelHandleTraits> createFileOrThrow(const std::string& filename, ... )
{
HANDLE handle;
if (!CreateFile(&handle, filename.c_str(), ...) {
throw suitable_exception_type();
}
return HandleWrapper<KernelHandleTraits>(handle);
}
HandleWrapper<KernelHandleTraits> hFile = CreateFileOrThrow("filename");
不过,最后一个选项确实需要HandleWrapper
有一个移动构造函数。
- 外壳包装器句柄/执行交互式命令管道C++ UNIX
- 如何获取边缘窗口句柄 (HWND)?
- 枚举进程模块在有效句柄上返回无效句柄
- 在 c/c++ 中打开 PhysicalDrive 的句柄并写入 MBR 的 linux 等效是什么?
- 从运行服务的应用程序代码中提取窗口句柄
- 在读取文件后重置句柄
- 是否有像地图这样的C++结构,但我得到的不是值的键,而是值的句柄?
- Microsoft ODBC 无法创建有效的句柄
- 我是否可以使用 win32 句柄以编程方式记录发送到/接收到 USB/COM 的内容
- 获取特定进程的句柄数
- C++ 创建 NdisProt 驱动程序的句柄
- 是否需要关闭来自 WinHTTP 异步的句柄?
- 句柄OK全部崩溃
- 我需要通过窗口句柄(HWND)获取文件,我该怎么办?
- 什么是 C# 等同于C++句柄
- 未知C++错误:致命错误:glibc检测到无效的stdio句柄
- 获取现有进程句柄
- GetModuleHandle() 无法检索由 "notepad.exe" 加载的"advapi32.dll"的句柄
- 更正GLSL无绑定纹理句柄中的结构布局
- Windows HANDLE RAII 管理,如果返回布尔值而不是句柄怎么办?