为什么 fclose 不将文件指针设置为 NULL?
我正在为 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当然,
delete fp
会导致崩溃。它没有被分配new
。仅对使用new
获得的内容或文档告诉您使用它的其他内容调用delete
。fopen
的文档从未告诉您使用delete
。所有文件的清理都是由fclose
执行的;调用它后,您无需执行任何其他操作即可释放与文件相关的资源。设置
fp = NULL
就可以了。这可能是可取的,以便这个“智能文件指针”的未来消费者可以检查该指针是否仍然有效。 (不过,使用reset
方法比使用析构函数更有用;在析构函数运行之后,不会有任何未来的指针类使用者,因为该对象不再存在。)但是fclose
本身无法执行此操作,因为fclose
不会通过引用接收其参数,即使接收到,它也无法使所有参数无效 文件指针的可能副本。回想一下,free
和delete
也不将其参数设置为NULL
。Of course
delete fp
is causing a crash. It wasn't allocated withnew
. Only calldelete
on something you got withnew
or with something else that the documentation told you to use it on. The documentation forfopen
never tells you to usedelete
. All cleanup for files is performed byfclose
; 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 areset
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.) Butfclose
can't do that itself becausefclose
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 thatfree
anddelete
don't set their arguments toNULL
, either.不,您不应该尝试
删除
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
.fp 不是由 C 运行时分配的,您不必释放它。 fclose 不会将其设置为 NULL,因为它不能将其设置为 null(它是指向 FILE 结构的指针,而不是指向 FILE *)。
FP 如何分配不是您关心的问题,它不是您与 API 签订的合同的一部分,因此不必担心。
附录:
fopen 返回一个指向 FILE 结构的指针。从哪里以及如何获得记忆并不重要。它很可能指向内存中的静态结构。但是,基本上,您不对该内存负责,因此您不应该弄乱它。
现在,实际的 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:
But, obviously, most folks don't do that, they simply use a local stack variable to manage that. Depends on the use case.
fopen
和fclose
使用FILE *
元素进行必要的动态内存管理,因此您不必调用delete
> 关于他们。如果需要,您可以在其中放入 NULL 值,以表明该文件尚未分配。fopen
andfclose
do the neccessary dynamic memory management withFILE *
elements, so you don't have to calldelete
on them. You can put a NULL value in them if you want, to signal that the file is not assigned, however.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 callednew
. If you're doing RAII, you should only assignnew
to smart pointers, and never calldelete
ever.