以安全的 C++ 方式获取 FILE*
Getting FILE* in a safe C++ way
有没有办法以现代 C++ 方式获取已打开文件的 FILE*
句柄?..我想避免使用 <cstdlib>
中的 std::fopen
,因为我已经被警告说它可能不安全。
我尝试检查是否有办法从 fstream
中检索 FILE*
,但似乎没有办法做到这一点。
I want to avoid using std::fopen
from <cstdlib>
as I've been warned that it's potentially unsafe.
fopen()
没有任何“不安全”的地方。它通过 C 标准成为 C++ 标准的一部分。
他们可能会说,使用 RAII 对象是管理资源(文件句柄)的最佳方式,尤其是当您在程序中使用异常时。
I tried checking if there's a way to retrieve FILE*
from fstream
but it seems there isn't a way to do that.
不是一个简单的、完全便携的。查看 this one.
等问题
如果你真的想要 FILE*
,请使用 C API。
有些乐趣。
namespace file {
template<auto f>
using constant = std::integral_constant< std::decay_t<decltype(f)>, f >;
using file_ptr = std::unique_ptr<std::FILE, constant<std::fclose>>;
FILE* unwrap( file_ptr const& ptr ) { return ptr.get(); }
template<class T> requires (!std::is_same_v< file_ptr, std::decay_t<T> >)
T&& unwrap( T&& t ) { return std::forward<T>(t); }
file_ptr wrap( FILE* ptr ) { return file_ptr(ptr); }
template<class T> requires (!std::is_same_v< file_ptr, std::decay_t<T> >)
T&& wrap( T&& t ) { return std::forward<T>(t); }
template<auto f>
auto call = [](auto&&...args){ return wrap( f( unwrap(decltype(args)(args))... ) ); };
// most FILE* operations can be rebound as follows:
auto open = call<std::fopen>;
auto close = call<std::fclose>;
auto getc = call<std::fgetc>;
auto putc = call<std::fputc>;
// any one that works with raw buffers (like std::fread or std::fwrite) needs more work
}
其核心是 unique_ptr<FILE, thing that calls fclose>
是一个质量不错的 FILE*
C++ 包装器。
然后我添加了一些机制,将 fgetc
和类似功能映射到 wrapping/unwrapping 他们在 file::file_ptr
上运行的机制。
现在你可以做:
auto pFile = file::open("hello.txt", "r");
auto pFile = file::open("hello.txt", "r");
auto pFileOut = file::open("world.txt", "w");
if (pFile)
{
while(auto c = file::getc(pFile))
{
file::putc(c, pFileOut);
}
}
更高级的版本会从函数指针中获取参数,将它们放入一个元组中,将它们映射到经过修改的参数的元组中。
所以
char*, int
将映射到 std::span<char>
。
call
助手而不是上面的天真东西会采用经过处理的参数,将它们映射到 C 样式参数的元组,将元组连接在一起,然后 std::apply
C 函数。然后映射 return 值。
call
通过一些工作甚至可以有一个固定的签名而不是 auto&&...
,所以 IDE 可以给出提示。
有没有办法以现代 C++ 方式获取已打开文件的 FILE*
句柄?..我想避免使用 <cstdlib>
中的 std::fopen
,因为我已经被警告说它可能不安全。
我尝试检查是否有办法从 fstream
中检索 FILE*
,但似乎没有办法做到这一点。
I want to avoid using
std::fopen
from<cstdlib>
as I've been warned that it's potentially unsafe.
fopen()
没有任何“不安全”的地方。它通过 C 标准成为 C++ 标准的一部分。
他们可能会说,使用 RAII 对象是管理资源(文件句柄)的最佳方式,尤其是当您在程序中使用异常时。
I tried checking if there's a way to retrieve
FILE*
fromfstream
but it seems there isn't a way to do that.
不是一个简单的、完全便携的。查看 this one.
等问题如果你真的想要 FILE*
,请使用 C API。
有些乐趣。
namespace file {
template<auto f>
using constant = std::integral_constant< std::decay_t<decltype(f)>, f >;
using file_ptr = std::unique_ptr<std::FILE, constant<std::fclose>>;
FILE* unwrap( file_ptr const& ptr ) { return ptr.get(); }
template<class T> requires (!std::is_same_v< file_ptr, std::decay_t<T> >)
T&& unwrap( T&& t ) { return std::forward<T>(t); }
file_ptr wrap( FILE* ptr ) { return file_ptr(ptr); }
template<class T> requires (!std::is_same_v< file_ptr, std::decay_t<T> >)
T&& wrap( T&& t ) { return std::forward<T>(t); }
template<auto f>
auto call = [](auto&&...args){ return wrap( f( unwrap(decltype(args)(args))... ) ); };
// most FILE* operations can be rebound as follows:
auto open = call<std::fopen>;
auto close = call<std::fclose>;
auto getc = call<std::fgetc>;
auto putc = call<std::fputc>;
// any one that works with raw buffers (like std::fread or std::fwrite) needs more work
}
其核心是 unique_ptr<FILE, thing that calls fclose>
是一个质量不错的 FILE*
C++ 包装器。
然后我添加了一些机制,将 fgetc
和类似功能映射到 wrapping/unwrapping 他们在 file::file_ptr
上运行的机制。
现在你可以做:
auto pFile = file::open("hello.txt", "r");
auto pFile = file::open("hello.txt", "r");
auto pFileOut = file::open("world.txt", "w");
if (pFile)
{
while(auto c = file::getc(pFile))
{
file::putc(c, pFileOut);
}
}
更高级的版本会从函数指针中获取参数,将它们放入一个元组中,将它们映射到经过修改的参数的元组中。
所以
char*, int
将映射到 std::span<char>
。
call
助手而不是上面的天真东西会采用经过处理的参数,将它们映射到 C 样式参数的元组,将元组连接在一起,然后 std::apply
C 函数。然后映射 return 值。
call
通过一些工作甚至可以有一个固定的签名而不是 auto&&...
,所以 IDE 可以给出提示。