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

C++ 为什么fclose不将文件指针设置为NULL?,c++,pointers,fclose,C++,Pointers,Fclose,我正在为文件*编写RAII包装。我注意到,当文件*在析构函数中关闭后被删除时,会导致未定义的行为(seg.fault或其他地方的错误)。我假设fclose会将文件*设置为NULL,但它没有设置 class smartFP { smartFP (const std::string& name) : fp (fopen(name.c_str(), "r") { } ~smartFP() { if (fp) { fclose(fp);

我正在为文件*编写RAII包装。我注意到,当文件*在析构函数中关闭后被删除时,会导致未定义的行为(seg.fault或其他地方的错误)。我假设fclose会将文件*设置为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;
};
class-smartFP{
smartFP(常量标准::字符串和名称)
:fp(fopen(name.c_str(),“r”)
{ }
~smartFP()
{ 
if(fp){
fclose(fp);

//删除(fp)当然
delete fp
会导致崩溃。它没有被分配
new
。只需调用
delete
就可以使用
new
或文档告诉您要使用它的其他内容。fopen
的文档从不告诉您使用
delete
。所有文件的清理工作都会进行由
fclose
执行;在调用文件相关资源后,无需执行任何其他操作即可释放该资源


设置
fp=NULL
很好。这可能是可取的,以便将来使用此“智能文件指针”的用户可以检查指针是否仍然有效。(不过,
reset
方法比析构函数更有用;析构函数运行后,指针类不会有任何未来的使用者,因为对象不再存在。)但是
fclose
本身无法做到这一点,因为
fclose
不会通过引用接收其参数,即使它接收了,也无法使文件指针的所有可能副本无效。请记住
free
delete
也不会将其参数设置为
NULL

不,您不应该E试图编写<代码>删除< /C>文件>它是C库数据结构,并不代表从C++代码>新的返回的指针。

FP没有被C运行时分配,你不必释放它。FSET不将它设置为NULL,因为它不能将它设置为NULL(它是指向文件结构的指针,而不是文件*)。 FP的分配方式与您无关,它不是API合同的一部分,所以不用担心

增编:

fopen返回指向文件结构的指针。它从何处以及如何获取内存并不重要。它很可能指向内存中的静态结构。但是,基本上,您不应对该内存负责,因此不应该弄乱它

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

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

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

fopen
fclose
使用
FILE*
元素进行必要的动态内存管理,因此您不必对它们调用
delete
。如果您使用ant,表示未分配文件。

1)fclose无法将文件*设置为NULL,因为它的参数是文件*,因此它按值接收文件*。由于它是副本,因此它无法更改指针,除非参数更改为文件*&。

2)在C++中,你几乎不调用<代码>删除>代码>除非你调用了代码>新的<代码>。如果你正在做RAII,你只应该把代码<新>代码>分配给智能指针,并且永远不要调用<代码>删除>代码>。为什么你要为文件*/COD>写一个RAII包装器?为什么你不使用C++?对旧软件进行分级是一个常见的原因。我已经这样做了。对一个文件*进行RAII比用流替换它要小得多。@Adam-MD是对的。用fstream替换现有的文件*需要更多的更改,特别是当一些读取二进制文件的库需要传递文件*时。我考虑了你提到的要点正在考虑在析构函数中将fp设置为NULL。我在smartFP类中有一个返回FILE*:FILE*get(){return fp;}的API。这样做的原因是执行smartFPObj.get()在使用文件*的现有代码中。我不希望有人保留fp的副本,并在smartFPObj超出范围后尝试使用它。你的
get
方法很好,但你在析构函数中的操作对你没有任何帮助。如果有人调用
get
并存储结果的副本,他们就有结果的副本。你可以更改UR <代码> FP>代码>变量,但不影响拷贝中的值。请考虑此代码:<代码>文件*fp= fOpen.(…);文件*b= FP;fCAMP(FP);fp=NULL;将
fp
设置为
NULL
不会更改
b
。无论
fp
是类的成员还是
b
的赋值是在调用某个
get
方法之后进行的。@srikrish仅仅因为您将类中的指针成员设置为NULL并不意味着他们保存的副本将设置为空。另外,Rob,
fclose
是一个C函数,因此它不可能通过引用接收
文件*
(当然可能需要
文件**
。@Rob-感谢您的澄清。因此,当我执行fp=fopen(…),是在调用函数的堆或堆栈上分配的fp。类似地,当您坐在“所有由fclose完成的文件的清理”位置时,这是否意味着为私有成员fp(在堆栈或堆中)分配了空间是取消分配还是以后再发生。@Rob-是否也会在堆栈或堆中为文件*b(fp的副本)分配空间?是否有允许此复制的文件*的复制分配运算符。正如我所解释的,删除fp的原因是释放fopen分配给私有成员fp的任何空间。因为,我认为fclose只会释放在内存中分配给文件的空间,我想删除fp并释放空间。现在还不清楚,为什么不需要。是因为fclose做这个工作。