开发者

why does fclose not set file pointer to NULL?

开发者 https://www.devze.com 2023-04-01 04:52 出处:网络
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 th

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号