Согласно этой ссылке на C++: http://www.cplusplus.com/reference/fstream/ofstream/ofstream/, режим открытия по умолчанию для std::ofstream — ios_base::out, и в нем не упоминаются другие неявные режимы. Поэтому я ожидаю, что если я перезапишу большой файл маленьким файлом, «превышающая» часть большого файла останется нетронутой, и только первая часть файла должна быть заменена новыми, более короткими данными.
С другой стороны, в Руководстве пользователя стандартной библиотеки Apache C++ (http://stdcxx.apache.org/doc/stdlibug/30-3.html) в примечании к параграфу 30.3.1.2 указано: «Для выходных файловых потоков открытый режим out эквивалентен out|trunc, то есть вы можете опустить флаг trunc Однако для двунаправленных файловых потоков trunc всегда должен указываться явно».
Я пробовал этот код:
#include <fstream>
int main()
{
std::ofstream aFileStream("a.out", std::ios_base::out);
aFileStream << "Hello world!";
aFileStream.close();
std::ofstream aFileStream2("a.out", std::ios::out);
aFileStream2 << "Bye!";
aFileStream2.close();
}
В обоих случаях, с g++ 8.1 в Windows и g++ 6.3 в Linux, документация Apache кажется правильной. Большой файл усекается, после записи более короткой строки вторым файловым потоком ничего не остается.
Почему это так? Сайт cplusplus.com неправильный? Или от чего зависит поведение?





За [ofstream.cons]/itemdecl:2:
explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
Поэтому режим по умолчанию для ofstream — out. Однако согласно [вкладка:filebuf.open.modes], out и out | trunc соответствуют эквиваленту stdio "w", поэтому они эквивалентны. Согласно С11 7.21.5.3:
w: truncate to zero length or create text file for writing
Таким образом, правильно сказать, что режим по умолчанию — это out, а также правильно сказать, что режим по умолчанию эквивалентен out | trunc. Это гарантированное поведение.
С другой стороны, согласно [fstream.cons]/itemdecl:2:
explicit basic_fstream( const char* s, ios_base::openmode mode = ios_base::in | ios_base::out);
Поэтому режим по умолчанию для fstream — in | out. Согласно [вкладка:filebuf.open.modes], in | out соответствует "r+", а in | out | trunc соответствует "w+", поэтому они не эквивалентны. Согласно С11 7.21.5.3:
r+: open text file for update (reading and writing)w+: truncate to zero length or create text file for update
Поэтому fstream не усекается, если вы не укажете trunc.
Обратите внимание, что если нужный файл не существует, вместо создания файла произойдет сбой r+. Напротив, в этом случае w и w+ создают новый файл.
(См. также: fopen в cppreference)
Отличный ответ. Не могли бы вы также связать цитируемый стандарт C? Это сделало бы ответ еще лучше.
@FelixDombek К сожалению, я не знаю об официальной черновой версии стандарта HTML C. PDF-версия окончательного проекта C11 доступна по адресу open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. Подожди секунду ...
@FelixDombek Добавлена ссылка на стандарт и cppreference.
Спасибо, круто. Подожди, а как работает имя твоего хеш-якоря?! Это совсем не похоже на стандарт, указанный в adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/….
@FelixDombek Magic :) Я использую Firefox, щелкаю правой кнопкой мыши на панели навигации слева и выбираю «Копировать ссылку», вот и все.
Еще один небольшой комментарий: возможно, стоит отметить, что в отличие от ofstream, fstream с in|out НЕ создаст файл, если он не существует (но вместо этого произойдет сбой). Так что это не замена 1:1.
@FelixDombek Уточнено.
Ваш ответ решил проблему, из-за которой был задан этот вопрос (смесь fopen и std::ofstream). Спасибо! :-)
В соответствии с cppreference выход удалит содержимое уже существующих файлов (таким образом, переопределив все)