Программирование >>  Разработка устойчивых систем 

1 ... 106 107 108 [ 109 ] 110 111 112 ... 196


Спасибо Натану Майерсу (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):



1 ... 106 107 108 [ 109 ] 110 111 112 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика