Несмотря на название, RAII не обязательно включает в себя приобретение ресурсов;
Например, std::shared_ptr
не делает new
. Имя
исторический, и картина действительно касается очистки.
В случае File
, конечно, «правильным» ответом является использование
std::ifstream
и std::ofstream
, и покончим с этим. А очень
важно (по крайней мере, для вывода): RAII может использоваться только для исключительных
очистка, так как вы должны убедиться, что close
правильно
закончил, прежде чем покинуть блок в обычном случае. В целом
правило, если закрыть не удается, вы хотите удалить файл (и вернуть
EXIT_FAILURE
из main
, или сделайте что-нибудь, что сделает ошибку
и препятствовать выполнению следующего кода, исходя из предположения, что
данные были написаны). Так что единственный раз, когда это было бы приемлемо для
отложить close
на деструктор в случае, когда вы уже
обнаружил ошибку и собираюсь удалить файл как часть очистки
в любом случае.
Как правило, выходные данные подчиняются модели транзакций, более чем RAII; я
как правило, обернуть мой std::ofstream
в классе OutputFile
, с
commit()
функция, которая закрывает файл и помечает класс как
совершено, если (и только если) успешное закрытие; если деструктор
вызван, и файл не был передан, деструктор закрывает
файл, а затем удаляет его. (Предположительно какой-то более высокий уровень будет ловить
исключение и преобразовать его в return EXIT_FAILURE
в основном.)
Кроме того, IO в целом немного исключительный. Обычно, если вы не можете
создать объект, по какой-либо причине, конструктор должен поднять
исключение; Вы не хотите, чтобы объекты "зомби" плавали вокруг, что не может
использоваться. В случае IO, однако, вы должны иметь дело с тем,
что объект может стать недействительным и непригодным после строительства, даже
когда строительство удастся. Так как вы должны постоянно проверять их
в любом случае (после каждого чтения на входе и после закрытия на выходе),
часто уместно просто установить некоторый внутренний флаг в объекте,
который вы тестируете.