1

我正在为 FILE * 编写一个 RAII 包装器。我注意到当 FILE * 在析构函数中关闭后被删除时,它会导致未定义的行为(例如错误或其他地方的错误)。我假设 fclose 会将 FILE * 设置为 NULL,但事实并非如此。

class smartFP {
  smartFP (const std::string& name) 
  : fp (fopen(name.c_str(), "r")
  { }

  ~smartFP()
  { 
     if (fp) {
        fclose(fp); 
        // delete(fp); <- This is causing crash
        fp = NULL; <- Is this OK?
     }
  }

private:
   FILE *fp;
};
  • 为什么 fclose 不将 FILE * 设置为 NULL?
  • 第二个问题是 fopen 是在堆还是栈中为 fp 分配内存?我认为它在堆上,因此想在 fclose 之后进行删除,以便释放 fp 堆上的 4 或 8 个字节。但看起来这不是必需的。
4

5 回答 5

14

当然delete fp是导致崩溃。它没有分配给new. 只调用delete你得到的new东西或文档告诉你使用它的其他东西。never的文档fopen告诉您使用delete. 文件的所有清理都由fclose; 在调用文件相关资源后,您无需执行任何其他操作来释放文件相关资源。

设置fp = NULL很好。这可能是可取的,以便这个“智能文件指针”的未来消费者可以检查指针是否仍然有效。(不过,方法比析构函数更有用reset;在析构函数运行后,指针类的任何未来消费者都不会再存在了,因为对象不再存在。)但是不能自己fclose这样做,因为fclose不' 不通过引用接收它的参数,即使它接收了,它也无法使文件指针的所有可能副本无效。回想一下,free也不delete要将他们的论点设置NULL为 。

于 2011-09-01T22:00:28.110 回答
2

不,您不应该尝试deleteFILE *. 它是 C 库数据结构,不代表从 C++ 返回的指针new

于 2011-09-01T22:01:53.383 回答
2

fp 不是由 C 运行时分配的,您不必释放它。fclose 没有将其设置为 NULL,因为它不能将其设置为 null(它是指向 FILE 结构的指针,而不是指向 FILE *)。

如何分配 FP 不是你关心的问题,它不是你与 API 合同的一部分,所以不用担心。

附加物:

fopen 正在返回一个指向 FILE 结构的指针。它在何处以及如何获取内存并不重要。它很可能指向内存中的静态结构。但是,基本上,你不对那段记忆负责,所以你不应该弄乱它。

现在,实际的 fp 指针,您可以分配它:

FILE **fp = malloc(sizeof(FILE *));
*fp = fopen("file.txt", "r");
...
fclose(*fp);
free(fp);

但是,显然,大多数人不这样做,他们只是使用本地堆栈变量来管理它。取决于用例。

于 2011-09-01T22:02:08.267 回答
1

fopenfclose使用元素进行必要的动态内存管理FILE *,因此您不必调用delete它们。但是,如果需要,您可以在其中放置一个 NULL 值,以表明该文件未分配。

于 2011-09-01T22:02:58.437 回答
1

1) fclose不能将 FILE* 设置为 NULL,因为它的参数是 FILE*,所以它按值接收 FILE*。因为它是一个副本,所以它不能改变你的指针,除非参数被改变为 FILE*&。
2)在 C++ 中,你几乎从不调用delete,除非你调用new. 如果你在做 RAII,你应该只分配new给智能指针,永远不要调用delete

于 2011-09-01T22:04:38.947 回答