Почему std::ofstream усекается без std::ios_base::trunc?

Согласно этой ссылке на C++: http://www.cplusplus.com/reference/fstream/ofstream/ofstream/, режим открытия по умолчанию для std::ofstreamios_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 неправильный? Или от чего зависит поведение?

В соответствии с cppreference выход удалит содержимое уже существующих файлов (таким образом, переопределив все)

DColt 17.07.2019 08:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
1
2 113
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

За [ofstream.cons]/itemdecl:2:

explicit basic_ofstream(const char* s,
                        ios_base::openmode mode = ios_base::out);

Поэтому режим по умолчанию для ofstreamout. Однако согласно [вкладка: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);

Поэтому режим по умолчанию для fstreamin | 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? Это сделало бы ответ еще лучше.

Felix Dombek 17.07.2019 09:46

@FelixDombek К сожалению, я не знаю об официальной черновой версии стандарта HTML C. PDF-версия окончательного проекта C11 доступна по адресу open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. Подожди секунду ...

L. F. 17.07.2019 09:48

@FelixDombek Добавлена ​​ссылка на стандарт и cppreference.

L. F. 17.07.2019 09:51

Спасибо, круто. Подожди, а как работает имя твоего хеш-якоря?! Это совсем не похоже на стандарт, указанный в adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/….

Felix Dombek 17.07.2019 09:54

@FelixDombek Magic :) Я использую Firefox, щелкаю правой кнопкой мыши на панели навигации слева и выбираю «Копировать ссылку», вот и все.

L. F. 17.07.2019 09:57

Еще один небольшой комментарий: возможно, стоит отметить, что в отличие от ofstream, fstream с in|out НЕ создаст файл, если он не существует (но вместо этого произойдет сбой). Так что это не замена 1:1.

Felix Dombek 17.07.2019 10:05

@FelixDombek Уточнено.

L. F. 17.07.2019 10:08

Ваш ответ решил проблему, из-за которой был задан этот вопрос (смесь fopen и std::ofstream). Спасибо! :-)

Benjamin Bihler 17.07.2019 10:16

Другие вопросы по теме