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 t开发者_JAVA百科hought 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.
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.
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 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.
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.
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.
精彩评论