|
Программирование >> Включение нужных заголовков
Но вскоре выясняется, что приведенный синтаксис не копирует в строку пропуски (whitespace), входящие в файл. Это объясняется тем, что i streamj terator производит непосредственное чтение функциями operator , а эти функции по умолчанию не читают пропуски. Чтобы сохранить пропуски, входящие в файл, достаточно включить режим чтения пропусков сбросом флага skipws для входного потока: i fstream inputFi1e( i nterestingData.txt ): inputFile.unset(ios::skipws): Включить режим чтения пропусков в inputFile string fileData(istreamjterator<char>(inputFile)), Прочитать inputFile istreamJterator<char>()): в fileData. Теперь все символы inputFile копируются в fileData. Кроме того, может выясниться, что копирование происходит не так быстро, как вам хотелось бы. Функции operator , от которых зависит работа istreami terator, производят форматный ввод, а это означает, что каждый вызов сопровождается многочисленными служебными операциями. Они должны создать и уничтожить объекты sentry (специальные объекты потоков ввода-вывода, выполняющие начальные и завершающие операции при каждом вызове operator ); они должны проверить состояние флагов, влияющих на их работу (таких, как skipws); они должны выполнить доскональную проверку ошибок чтения, а в случае обнаружения каких-либо проблем - проанализировать маску исключений потока и определить, нужно ли инициировать исключение. Все перечисленные операции действительно важны при форматном вводе, но если ваши потребности ограничиваются чтением следующего символа из входного потока, без них можно обойтись. Более эффективное решение основано на использовании неприметного итератора 1 str eambufi terator. Итераторы istreambuf i terator работают аналогично istreami terator, но если объекты istream iterator<char> читают отдельные символы из входного потока оператором , то объекты istreambuf i terator обращаются прямо к буферу потока и непосредственно читают следующий символ (выражаясь точнее, объект istreambuf iterator<char> читает следующий символ из входного потока s вызовом s. rdbuf () ->sgetc()). Перейти на использование istreambufj terator при чтении файла так просто, что даже программист Visual Basic сделает это со второй попытки: ifstream inputFi1е( interestingData.txt ); stri ng fi1eData(1streambuf i terator<char>(i nputFi 1 e)). istreambufjterator<char>()): Ha этот раз сбрасывать флаг skipws не нужно, итераторы istreambuf iterator никогда не пропускают символы при вводе и просто возвращают следующий символ из буфера. По сравнению с i str eami terator это происходит относительно быстро. В проведенных мною простейших тестах выигрыш по скорости достигал 40%, хотя в вашем случае цифры могут быть другими. Не удивляйтесь, если быстродействие будет расти со временем; итераторы istreambuf iterator населяют один из заброшенных уголков STL, и авторы реализаций еще недостаточно позаботились об их оптими- зации. Например, в моих примитивных тестах итераторы istreambufi terator одной из реализаций работали всего на 5% быстрее, чем istreami terator. В таких реализациях остается широкий простор для оптимизации istreambuf i terator. Если вы планируете читать из потока по одному символу, не нуждаетесь в средствах форматирования ввода и следите за эффективностью выполняемых операций, три лишних символа на итератор - не такая уж дорогая цена за заметный рост быстродействия. При неформатном посимвольном вводе всегда рассматривайте возможность применения istreambuf iterator. Раз уж речь зашла о буферизованных итераторах, следует упомянуть и об использовании ostreambuf iterator при неформатном посимвольном выводе. По сравнению с ostreami terator итераторы ostreambufi terator обладают меньшими затратами (при меньших возможностях), поэтому обычно они превосходят их по эффективности. Алгоритмы В начале главы 1 я упоминал о том, что львиная доля репзггации STL связана с контейнерами, и это вполне объяснимо. Контейнеры обладают массой достоинств и упрощают повседневную работу бесчисленных программистов С++. Но и алгоритмы STL тоже по-своему замечательны и в той же степени облегчают бремя разработчика. Существует более 100 алгоритмов, и встречается мнение, что они предоставляют программисту более гибкий инструментарий по сравнению с контейнерами (которых всего-то восемь!). Возможно, недостаточное применение алгоритмов отчасти и объясняется их количеством. Разобраться в восьми типах контейнеров проще, чем запомнить имена и предназначение многочисленных алгоритмов. В этой главе я постараюсь решить две основные задачи. Во-первых, я представлю некоторые малоизвестные алгоритмы и покажу, как с их помощью упростить себе жизнь. Не беспокойтесь, вам не придется запоминать длинные списки имен. Алгоритмы, представленные в этой главе, предназначены для решения повседневных задач - сравнение строк без зета регистра символов, эффективный поиск п объектов, в наибольшей степени соответствующих заданному критерию, обобщение характеристик всех объектов в заданном интервале и имитация copyi f (алгоритм из исходной реализации HP STL, исключенный в процессе стандартизации). Во-вторых, я назу вас избегать стандартных ошибок, возникающих при работе с алгоритмами. Например, при вызове алгоритма гепюуе и его родственников remove if и unique необходимо точно знать, что эти алгоритмы делают (и чего они не делают). Данное правило особенно актуально при вызове remove для интервала, содержащего указатели. Многие алгоритмы работают только с отсортированными интервалами, и программист должен понимать, что это за алгоритмы и почему для них установлено подобное ограничение. Наконец, одна из наиболее распространенных ошибок, допускаемых при работе с алгоритмами, заключается в том, что программист предлагает алгоритму записать результаты своей работы в несуществующую область памяти. Я покажу, как это происходит и как предотвратить эту ошибку.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |