|
Программирование >> Разработка устойчивых систем
Спасибо Натану Майерсу (Nathan Myers) за это объяснение. using namespace std: int mainO { i fstream in( StreambufIterator.cpp ): assuredn. Streambuflterator.cpp ): Точное представление потока: istreambuf iterator<char> isb(in), end: ostreambuf iterator<char> osb(cout): whiledsb != end) *osb++ = *isb++: Копирование in в cout cout endl: ifstream in2( StreambufIterator.cpp ): Удаление пропусков: istream iterator<char> is(in2), end2: ostream iterator<char> os(cout): while(is != end2) *os++ = *1s++; cout endl: } III:- Правила синтаксического разбора для потоковых итераторов определяет оператор istream::operator . Если вы самостоятельно обрабатываете символьные данные, вряд ли вас это устроит - не так уж часто требуется удалять из входного потока символов все пропуски. При работе с символами вместо обычных потоковых итераторов почти всегда используются буферные итераторы streambuf. Вдобавок оператор istream::operator существенно замедляет выполнение всех операций вывода, поэтому он применяется только при высокоуровневых операциях (например, выборке чисел из входного потока). Работа с блоками памяти Итератор raw storage iterator определяется в заголовке <memory> и относится к категории итераторов вывода. Он позволяет алгоритмам сохранять результаты своей работы в неинициализированной памяти. Интерфейс этого итератора достаточно прост: конструктору передается итератор вывода, указывающий на физический блок памяти (как правило - указатель), а оператор = записывает объект в указанный блок. Параметры щаблона определяют тип итератора вывода, ссылающегося на блок памяти, и тип сохраняемого объекта. В следующем примере создаются объекты Noisy, которые выводят сообщения о своем конструировании, присваивании и уничтожении (определение класса Noisy будет приведено позднее): : C07:RawStorageIterator.cpp {-Ьог} Использование raw storage iterator {L} Noisy linclude <iostream> #i nclude <iterator> linclude <algoritlim> linclude Noisy.h using namespace std: int mainO { const int quantity = 10: Выделение памяти и приведение к нужному типу: Noisy* пр = rei nterpret cast<Noi sy*>( new char[quantity * slzeof(Noisy)]); raw storage iterator<Noisy*. No1sy> rsi(np); fordnt i = 0: i < quantity: i++) *rsi++ - NoisyO: Сохранение объектов в памяти cout endl: copy(пр. np + quantity. ostream iterator<Noisy>(cout. )): cout endl: Явный вызов деструктора: for(int j - 0: j < quantity: (&np[j])->-No1sy(): Освобождение памяти: delete reinterpret cast<char*>(np): } III:- Шаблон raw storageJterator требует, чтобы выделенная память соответствовала типу создаваемых объектов, поэтому указатель на созданный массив char преобразуется в указатель Noisy*. Оператор присваивания сохраняет объекты в выделенной памяти с использованием копирующего конструктора. Обратите внимание на необходимость явного вызова деструктора для освобождения выделенной памяти; это также позволяет удалять объекты по одному в процессе операций с контейнером. Выражение delete пр все равно было бы недопустимым, поскольку статический тип указателя в выражении с оператором delete должен совпадать с типом, которому присваивалось значение в выражении с оператором new. Основные последовательные контейнеры Последовательные контейнеры (вектор, список, дек) хранят объекты в порядке их занесения в контейнер. Однако они различаются по эффективности операций, и если вы собираетесь выполнять с контейнером множество однотипных операций, выберите ту разновидность контейнера, в которой эти операции выполняются эффективнее всего. До сих пор во всех приводимых примерах мы использовали контейнер vector; и в самом деле, на практике векторы применяются чаще других разновидностей контейнеров. Но постепенно вы начнете осваивать нетривиальные возможности контейнеров, и чтобы принять правильное рещение, вам нужно будет больще знать об особенностях реализации и поведения основных разновидностей контейнеров. Базовые операции в последовательных контейнерах В следующем примере продемонстрированы операции, поддерживаемые всеми основными последовательными контейнерами: векторами, деками и списками. : C07:BasicSequenceOperations.cpp Операции, доступные для всех основных последовательных контейнеров. linclude <deque> linclude <iostream> linclude <list> linclude <vector> using namespace std: tempiate<typename Container> void print(Container& с. char* title = ) { cout title : endl: if(c.empty()) { cout (empty) endl: return: typename Container::iterator it: for(it = c.beginO: it != c.endO: it++) cout *it : cout endl: cout SizeO c.SizeO max size() c.max size() front О с. front О back О с.back О endl: tempiate<typename ContainerOfInt> void basicOps(char* s) { cout ....... s ....... endl: typedef ContainerOfInt Ci: Ci c: printCc. c after default constructor ): Ci c2(10. 1): 10 элементов со значением 1 print(c2. c2 after constructor(lO.l) ): int ia[] = { 1. 3. 5. 7. 9 }: const int iasz = sizeof(ia)/sizeof(*ia): Инициализация с начальным и конечным итераторами: Ci c3(ia. ia + iasz): print(c3. c3 after constructor(iter.iter) ): Ci c4(c2): Копирующий конструктор print(c4. c4 after copy-constructor(c2) ): с = c2: Оператор присваивания printCc. с after operator=c2 ): c.assignClO. 2): 10 элементов со значением 2 printCc. с after assigndO. 2) ): Присваивание с начальным и конечным итераторами: c.assignCia. ia + iasz): printCc. с after assignCiter. iter) ): cout c using reverse iterators: endl: typename Ci::reversejterator rit = c.rbeginO: whileCrit != c.rendO) cout *rit++ : cout endl: c.resizeC4): printCc. c after resizeC4) ): c.push backC47): printCc. c after push backC47) ): с.pop back С): printCc. c after pop backC) ): typename Ci::iterator it = c.beginC): ++it: ++it: c.insertCit. 74): printCc. c after insertCit. 74) ): it = C.beginC): ++it: C.insertCit. 3. 96): printCc. c after insertCit. 3. 96) ): it = C.beginC):
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |