Во-первых: вы не можете сделать что-нибудь полезное с ошибкой, если ваш файловый объект GCed и не может закрыть ФАЙЛ *. Таким образом, оба эквивалентны, насколько это возможно.
Во-вторых, «правильный» шаблон выглядит следующим образом:
class X{
FILE *fp;
public:
X(){
fp=fopen("whatever","r");
if(fp==NULL) throw some_exception();
}
~X(){
try {
close();
} catch (const FileError &) {
// perhaps log, or do nothing
}
}
void close() {
if (fp != 0) {
if(fclose(fp)!=0){
// may need to handle EAGAIN and EINTR, otherwise
throw FileError();
}
fp = 0;
}
}
};
Использование:
X x;
// do stuff involving x that might throw
x.close(); // also might throw, but if not then the file is successfully closed
Если выдает «do stuff», то не имеет значения, был ли дескриптор файла закрыт успешно или нет. Операция не удалась, поэтому файл в любом случае обычно бесполезен. Кто-то наверху цепочки вызовов может знать, что с этим делать, в зависимости от того, как используется файл - возможно, его следует удалить, возможно, оставить в покое в его частично написанном состоянии. Что бы они ни делали, они должны знать, что в дополнение к ошибке, описанной в исключении, которое они видят, возможно, что файловый буфер не был очищен.
RAII используется здесь для управления ресурсами . Файл закрывается несмотря ни на что. Но RAII не используется для определения того, успешно ли выполнена операция - если вы хотите это сделать, вы вызываете x.close()
. GC также не используется для определения того, была ли операция успешной, поэтому оба значения равны по этому количеству.
Подобная ситуация возникает, когда вы используете RAII в контексте, где вы определяете какую-либо транзакцию - RAII может откатить открытую транзакцию для исключения, но, если все идет хорошо, программист должен явно зафиксировать транзакцию .
Ответ на ваш вопрос - преимущество RAII и причина, по которой вы заканчиваете сбросом или закрытием файловых объектов в предложениях finally
в Java, заключается в том, что иногда вы хотите, чтобы ресурс был очищен (насколько это возможно). может быть) немедленно при выходе из области видимости, чтобы следующий бит кода знал, что это уже произошло. Mark-sweep GC не гарантирует этого.