最近我在工作中遇到了一个问题,你有两个功能;一个打开文件描述符(它是函数中的局部变量),并将其传递给另一个用于读取或写入的函数。现在,当其中一个操作读/写失败时,正在执行读/写操作的函数将关闭此文件描述符,然后返回。 问题是,其职责是关闭文件描述符,或者让我们说清理:
创建fd的功能
读/写时遇到错误的功能
这类案件是否有设计规则;让我们说创造和清理。
顺便说一下,问题是这两个函数都试图关闭fd,导致第二次关闭调用崩溃。答案 0 :(得分:0)
这个答案有两个部分 - 一般设计问题和适合您情况的详细机制。
正确处理文件描述符等资源,并确保正确发布它们是一个重要的设计问题。有多种方法可以解决有效的问题。还有一些其他人不会。
您的代码使用C和C ++;请注意,C ++有额外的机制可用。
在C ++中,RAII - 资源获取是初始化 - 成语是一个很好的帮助。获取资源时,确保获取资源的任何内容都初始化一个将被正确销毁的值,并在销毁时释放资源。
在这两种语言中,通常最好是负责分配资源的函数也释放它。如果函数打开文件,它应该关闭它。如果函数被赋予打开文件,则不应该关闭该文件。
在评论中,我写道:
通常,打开文件的功能应该关闭它;遇到错误的函数应该报告错误,但不能关闭文件。但是,只要合同被记录并强制执行,您就可以按照自己的方式工作 - 调用代码需要知道被调用代码何时关闭文件以避免双重关闭。
对于被调用函数来说,有时(出错时)关闭文件通常是一个糟糕的设计,但不是其他时间(没有错误)。如果你必须这样做,那么通知调用函数文件被关闭是至关重要的;被调用的函数必须返回一个错误指示,告诉调用代码该文件不再有效,既不应该使用也不应该关闭。只要信息被中继和处理,就没有问题 - 但功能更难使用。
请注意,如果函数被设计为返回已打开的资源(它是一个负责打开文件并使其可用于调用它的函数的函数),那么关闭文件的责任就会降低在调用open函数的代码上。这是一个合法的设计;你只需要确保有一个知道如何关闭它的函数,并且调用代码会关闭它。
类似的评论适用于内存分配。如果函数分配内存,则必须知道何时释放内存,并确保释放它。如果它是为了当前函数和它调用的函数的目的而分配的,那么应该在返回之前释放内存。如果它被分配给调用函数使用,则释放的责任转移到调用函数。
您确定使用的是文件描述符,而不是FILE *
(文件流)吗?关闭文件描述符两次不太可能导致崩溃(错误,是的,但不是崩溃)。 OTOH,在已经关闭的文件流上调用fclose()
可能会导致问题。
通常,在C中,您通过值传递文件描述符(小整数),因此没有办法告诉调用函数文件描述符不再有效。在C ++中,您可以通过引用传递它们,但这样做并不常见。与FILE *
类似;它们最常通过值传递,而不是通过引用传递,因此通过修改传递给函数的值,没有办法告诉调用代码文件不再可用。
您可以通过将文件描述符设置为-1
来使其无效;这绝不是有效的文件描述符。使用0
是一个坏主意;它相当于使用标准输入。您可以通过将文件流设置为0
(又名NULL
)来使文件流无效。将空指针传递给尝试使用文件流的函数将导致崩溃。传递无效的文件描述符通常不会导致崩溃 - 调用可能会在EBADF
中设置为errno
时失败,但这通常是损坏的限制。
使用文件描述符,您很少会崩溃,因为文件描述符不再有效。使用文件流时,如果尝试使用无效的文件流指针,则会出现各种错误。