Дан текстовый файл
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Ребята кто прошаренный в С++ помогите пожалуйста. С чего начать? что делать?
1. Дан текстовый файл, нужно информацию из него перезаписать в обратном порядке в новый файл.
2. Дан текстовый файл, нужно информацию из него перезаписать в новый файл только цифры.
Круто! )) Мне даже показалось, что слишком круто...
Сначала то, что не понял:
Зачем template в
read_all_from_stream
? Мне кажется, что вполне хватило быstd::string read_all_from_stream(istream &&stream)
. Не?Зачем в переметрах функций используется
const std::string &
, когда хватило быconst char *
? Вроде проще передать указатель на С-строку, чем сначала сконструировать из С-строк std::string, а потом уже передавать адреса при вызове функций.Теперь, что показало тестирование.
Win 10 x64 ver. 1703, MS Visual Studio Community 2017. (Подозреваю, что сейчас в меня полетят гнилые яблоки, но тем не менее, компилятор С++ от MS — промышленный стандарт для разработки под Windows. И другого компилятора все равно под рукой нет.)
В Debug-конфигурации программа падает по assert'у, если в файле есть кириллица. В моем случае, никакого юникода, всё в cp1251. В Release — работает. Лечится заменой
::isdigit
на[](char a) { return a >= '0' && a <= '9'; }
. Пробовалsetlocale(LC_ALL, "Russian")
— не помогает.Попробовал в качестве входного файла подсунуть текстовый файл размером 1Gb. Если компилить x64, то работает. При этом занимает 984580К оперативы. Если компилить в x86, то после запуска программа очень долго думает (несколько десятков минут; точно время не засекал), занимая 691148К памяти, пототм выдает bad allocation и умирает.
Мне кажется, всасывать в std::string весь файл целиком — не лучшая идея.
Конкретно для этого примера хватило бы. А вообще код переделан из другого, поэтому там еще вызовы clear и str остались.
Если путь собирается из частей, то мороки с указателями больше. А что касается данного примера, то всё равно не будет аллокаций памяти для std::string.
Этот assert на cl достал в своё время. Он считает, что при использовании char код символа не должен быть больше 127 (то бишь меньше нуля). В Release этот assert выпиливается. И программа не падает, там есть кнопочка «Продолжить». Это типа нас так предупреждают.
И не поможет. Скорее всего оно еще и с кириллаческими путями работать не будет, потому что для винды придется конвертировать в wchar_t. )))
В данном случае нам нужно поместить в std::string весь этот гигабайт, что мы успешно и делаем. Работа с большими файлами требует другой организации чтения и записи, при этом код усложниться.
Потому что винда любит свой swap-файл до изнеможения задрочить. )))
Для мелких файлов — отлично, для больших алгоритм нужно изменять, причем существенно. Но файл текстовый, много гигабайт такие файлы, обычно, занимают, только если это таблицы для brootforce'а )))
Там в сообщении написано что-то типа
c > -1 && c <= 255
. Т.е. по-видимому, задействовано преобразованиеchar -> int
, при котором происходит расширение знака.Причём здесь своп? 32-разрядная версия тупо не может выделить память под буфер строки «слишком» большого размера. Непонятно только почему она не вываливается после первой же неудачи. Исключение там генерируется, судя по логам VS, но видимо где-то там, во глубине, и перехватывается. Вообще мне кажется, что то исключение, которое перехватывает catch в main, это ошибка распределения памяти при генерации множественных объектов исключений в new.
Точнее, память под буфер stringstream.
Именно. Знаковый char расширяется, но проблема в том, что они же знают, что он знаковый и что будет так расширяться. А значит при любом значении char более 127 (менее 0), получим такой assert. )))
Ей 2Gb положено. Если нету — bad_alloc (под линуксом не всегда, под виндой не знаю), а вот тупить она начнет, когда будет задействован swap. Хотя понятие «тупить» у каждого разное.
Это ж американцы!.. Они не знают дальше ASCII7 ((
В своп она не лезет. Нет обмена с диском.
А вот на счёт 2Gb — здесь вот ворос интересный. 2Gb чего? Код + стек + куча? У меня программа занимает памяти 691Mb, когда начинаются тормоза. Выше этого объем занимаемой памяти не поднимается (по Task Manager). Если не отжирать такой буфер, то программа занимает порядка 450Kb (~0.5Mb) памяти. А если сделать логгирование new/delete (перегрузить стандартные new и delete), то получается следующее:
Здесь
new(размер_запрвшиваемой_памяти) -> адрес_выделенной_памяти
и
delete(адрес_освобождаемого_блока)
.Кстати, в случае перегруженных new/delete (самая примитивная реализация через malloc/free) исключение появляется достаточно быстро, но почему-то не ловится по
catch
, а просто крашит приложение.Как видно, последний успешный new получил 674Mb, а следующий запросил 1011Mb и обломился. Видимо стандартный new при невозможности выделить нужный кусок памяти запускает процедуру дефрагментации кучи, что выливается сначала в дикий тормоз, а потом в
bad_alloc
.Это тогда хорошо.
Далее, например, добавляем что-то в стрингу, лезем за гигом памяти. Нужен такой непрерывный участок для строки. Попробуй найди. Менеджер памяти в шоке, но работать надо. Именно по этому мне не всегда подходят стандартные контейнеры — слишком большой размах расширения. От 1.6 до 2 раз хорошо подходит для мелких участков, а для больших объемов этого уже много. Например, у нас вектор на гиг, коэффициент расширения 1.6. Это значит, что для следующего расширения ему нужно еще 1.6 Гб памяти. Итого для вставки реаллокации потребуется держать занятой 2.6 Гб.
Стандартный оператор new — нет. Такими манипуляциями занимается менеджер памяти системы, которому надо найти огромный непрерывный кусок памяти (упрощенно обзовём это дело именно так).
Для справки, оператор new может и не выкинуть исключение в случае неудачи. Причем он сам не в состоянии отследить неудачное выделение.
Стандартные операторы new и delete могут быть, и, скорее всего, будут устроены значительно сложнее.
Скучно здесь и не интересно. :(