以安全的C++方式获取FILE*

4
有没有一种现代C ++的方式来获取已打开文件的FILE*句柄?我希望避免使用来自<cstdlib>std::fopen,因为有人警告说它可能不安全。
我尝试检查是否有一种方法可以从fstream中检索FILE*,但似乎没有这样的方法。

4
C++ 的做法根本不涉及 FILE*。 - sweenish
那么在C++中没有办法获取FILE*吗?因为仍然有一些函数甚至是boost库利用它。 - Jack Avante
我很好奇你所指的功能是什么,以及你所提到的boost库是否已被标准库中的某些内容取代。当然,您仍然可以使用FILE*,但是您需要引入那些C头文件才能这样做。 - sweenish
FILE* 是 C 语言的,而不是 C++。C++ 处理文件的方式是使用 std::(i|o)fstream - Remy Lebeau
2
关于“被警告是潜在不安全的”的问题,有什么方面是“不安全”的?C程序员如何应对这种“不安全性”? - Pete Becker
2个回答

3
我希望避免使用 <cstdlib> 中的 std::fopen,因为有人警告说它可能不安全。 fopen() 并没有什么“不安全”的问题。这是通过 C 标准成为 C++ 标准的一部分。
他们可能想说的是最好使用 RAII 对象来管理资源(文件句柄),特别是如果程序中使用了异常。
检查是否有一种方法可以从 fstream 检索 FILE*,但似乎没有完全可移植的简单方法。参见像 这样的问题
如果你真的需要一个 FILE*,请使用 C API。

1
一些有趣的东西。
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,调用fclose的东西>是一个质量不错的FILE* C++封装器。

然后我添加了一些机制,将fgetc和类似函数映射到操作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函数。 然后映射返回值。

call通过一些工作甚至可以具有固定的签名,而不是auto&&...,因此IDE可以提供提示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接