此前:
Proper way close WinAPI HANDLEs (avoiding of repeated closing)
我的问题是:如果CreateFile返回一个bool而不是HANDLE,并且输出有一个指针怎么办?发明的例子:
HANDLE handle;
if (CreateFile(&handle, "filename", ...) == true) {
//...
}
使用提供的RAII类在C ++中使用它有一个很好的语法吗?这样我就可以将我的对象作为第一个参数而不是指针。
答案 0 :(得分:0)
你想要的是一个调用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
才能拥有移动构造函数。
答案 1 :(得分:0)
在这种情况下,我只需向RAII类添加一个覆盖operator&
,例如:
template< class traits >
class HandleWrapper {
...
public:
...
traits::HandleType* operator&() { return &FHandle; }
};
然后像这样使用它:
HandleWrapper<KernelHandleTraits> handle;
if (CreateFile(&handle, "filename", ...) == true) {
...
}
答案 2 :(得分:0)
你可以用其他人提到的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(资源分配是初始化)。
如果你有一个函数将资源返回为&#34;输出参数,&#34;你可以写一个适配器功能:
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;
}
};
请注意,我已将适配器功能设为私有静态,以确保没有人以不安全的方式使用它。
答案 3 :(得分:-1)
Windows API很好,但你看一下Boost library for filesystem operations。它是跨平台的这种操作的抽象。