为什么 fclose 不将文件指针设置为 NULL?

发布于 2024-12-02 13:49:05 字数 574 浏览 1 评论 0原文

我正在为 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 个字节。但看起来这个没有必要。

I was writing a RAII wrapper for FILE *. I noticed that when the FILE * is deleted after close in the destructor it leads to undefined behavior (seg. fault or errors somewhere else). I assumed that the fclose will set the FILE * to NULL, which it did not.

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;
};
  • Why does fclose not set the FILE * to NULL?
  • The second question is does fopen allocate memory for fp in the heap or stack? I thought it does on heap and hence wanted to do a delete after fclose, so that the 4 or 8 bytes on heap for fp is de-allocated. But looks like this is not needed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一花一树开 2024-12-09 13:49:05

当然,delete fp 会导致崩溃。它没有被分配new。仅对使用 new 获得的内容或文档告诉您使用它的其他内容调用 deletefopen 的文档从未告诉您使用 delete。所有文件的清理都是由fclose执行的;调用它后,您无需执行任何其他操作即可释放与文件相关的资源。

设置fp = NULL就可以了。这可能是可取的,以便这个“智能文件指针”的未来消费者可以检查该指针是否仍然有效。 (不过,使用 reset 方法比使用析构函数更有用;在析构函数运行之后,不会有任何未来的指针类使用者,因为该对象不再存在。)但是fclose 本身无法执行此操作,因为 fclose 不会通过引用接收其参数,即使接收到,它也无法使所有参数无效 文件指针的可能副本。回想一下,freedelete 也不将其参数设置为 NULL

Of course delete fp is causing a crash. It wasn't allocated with new. Only call delete on something you got with new or with something else that the documentation told you to use it on. The documentation for fopen never tells you to use delete. All cleanup for files is performed by fclose; there's nothing additional you need to do to release file-related resources after you've called it.

Setting fp = NULL is fine. It's probably desirable so that future consumers of this "smart file pointer" can check whether the pointer is still valid. (It's more useful from a reset method than from the destructor, though; there can't be any future consumers of the pointer class after the destructor has run because the object doesn't exist anymore.) But fclose can't do that itself because fclose doesn't receive its parameter by reference, and even if it did, it wouldn't be able to invalidate all possible copies of the file pointer. Recall that free and delete don't set their arguments to NULL, either.

苦行僧 2024-12-09 13:49:05

不,您不应该尝试删除 FILE *.它是一个 C 库数据结构,并不表示从 C++ new 返回的指针。

No, you should not be attempting to delete a FILE *. It is a C library data structure and does not represent a pointer returned from a C++ new.

愚人国度 2024-12-09 13:49:05

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);

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

fp isn't allocated by the C runtime, you don't have to free it. fclose doesn't set it to NULL because it CAN'T set it to null (it's a pointer to a FILE structure, not to a FILE *).

How FP is allocated isn't a concern to you, it's not part of your contract with the API, so don't worry about it.

Addenda:

fopen is returning a pointer to a FILE structure. Where and how it gets the memory is not important. It could well be pointing to a static structure in memory. But, basically, you're not responsible for that memory, so you should not mess with it.

Now, the actual fp pointer, you COULD allocate that:

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

But, obviously, most folks don't do that, they simply use a local stack variable to manage that. Depends on the use case.

入画浅相思 2024-12-09 13:49:05

fopenfclose 使用 FILE * 元素进行必要的动态内存管理,因此您不必调用 delete > 关于他们。如果需要,您可以在其中放入 NULL 值,以表明该文件尚未分配。

fopen and fclose do the neccessary dynamic memory management with FILE * elements, so you don't have to call delete on them. You can put a NULL value in them if you want, to signal that the file is not assigned, however.

夏日浅笑〃 2024-12-09 13:49:05

1) fclose不能将FILE*设置为NULL,因为它的参数是FILE*,所以它通过值接收FILE*。由于它是副本,因此无法更改指针,除非参数更改为 FILE*&。
2) 在 C++ 中,除非调用 new,否则您几乎永远不会调用 delete。如果您正在执行 RAII,则应该只将 new 分配给智能指针,并且永远不要调用 delete

1) fclose can't set the FILE* to NULL, because it's parameter is a FILE*, so it recieves the FILE* by value. Since it's a copy, it cannot alter your pointer, unless the parameter was changed to a FILE*&.
2) In C++, you pretty much never call delete unless you called new. If you're doing RAII, you should only assign new to smart pointers, and never call delete ever.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文