Чтение онлайн

ЖАНРЫ

Эффективное использование STL
Шрифт:

Итак, что же мы узнали?

• Класс строки без учета регистра символов реализуется на неправильном уровне абстракции. Обобщенные алгоритмы стандартной библиотеки C++ параметризуются, и этот факт следует использовать.

• Лексикографическое сравнение строк осуществляется сравнением отдельных символов. Если у вас имеется объект функции, сравнивающий символы без учета регистра, задача фактически решена, а этот объект может использоваться для сравнения других типов последовательностей символов, таких как

vector<char>
, строковые таблицы или обычные строки C.

• Задача сравнения строк без учета регистра

сложнее, чем кажется на первый взгляд. Она имеет смысл лишь в конкретном локальном контексте, поэтому объект функции сравнения должен содержать информацию о текущем локальном контексте. Если сравнение должно быть оптимизировано по скорости, напишите объект функции таким образом, чтобы избежать многократного вызова дорогостоящих операций с фасетами.

Правильное сравнение строк без учета символов требует большого объема рутинной работы, но ее необходимо проделать только один раз. Или вам, как и большинству коллег, не хочется думать о локальных контекстах? Впрочем, лет десять назад никому не хотелось думать об «ошибке 2000 года». И все же у вас больше шансов обойти стороной эту проблему, если ваш локально-зависимый код будет с самого начала правильно работать.

Замечания по поводу платформ STL от Microsoft

В начале книги я ввел термин «платформа STL», означающий комбинацию конкретного компилятора и конкретной реализации STL. Различие между компилятором и библиотекой особенно важно при использовании компилятора Microsoft Visual C++ версий 6 и ниже (то есть компилятора, входившего в комплект поставки Microsoft Visual Studio версий 6 и ниже), поскольку компилятор иногда способен на большее, чем прилагаемая реализация STL. В настоящем приложении описаны важные недостатки старых платформ STL от Microsoft и предложены обходные решения, делающие работу на этих платформах значительно более удобной.

Дальнейший материал предназначен для разработчиков, использующих Microsoft Visual C++ (MSVC) версий 4-6. В Visual C++ .NET перечисленные проблемы отсутствуют.

Шаблоны функций классов в STL

Допустим, у вас есть два вектора объектов

Widget
, требуется скопировать объекты
Widget
из одного вектора в конец другого. Задача решается легко — достаточно воспользоваться интервальной функцией
insert
контейнера
vector
:

vector<Widget> vw1, vw2;

vw1.insert(vw1.end, vw2.begin, vw2.end); // Присоединить к vw1 копию

// объектов Widget из vw2

Аналогичную операцию можно выполнить с контейнерами

vector
и
deque
:

vector<Widget> vw;

deque<Widget> dw;

vw.insert(vw.end, dw.begin, dw.end); // Присоединить к vw копию

// объектов Widget из dw

Оказывается, эту операцию можно выполнить независимо от того, в каких контейнерах хранятся копируемые объекты. Подходят даже нестандартные контейнеры:

vector<Widget> vw;

list<Widget> lw;

vw.insert(vw.begin, lw.begin, lw.end); //
Присоединить к vw копию

// объектов Widget из lw

set<Widget> sw;

vw.insert(vw.begin, sw.begin, sw.end); // Присоединить к vw копию

// объектов Widget из sw

template<typename T,

 typename Allocator = allocator<T> > // Шаблон нестандартного

 class SpecialContainer{…}; // STL-совместимого контейнера

SpecialContainer<Widget> scw;

vw.insert(vw.begin, scw.begin, scw.end); // Присоединить к vw копию

// объектов Widget из scw

Подобная универсальность объясняется тем, что интервальная функция

insert
контейнера
range
вообще не является функцией в общепринятом смысле. Это шаблон функции контейнера, специализация которого с произвольным типом итератора порождает конкретную интервальную функцию
insert
. Для контейнера
vector
шаблон
insert
объявлен в Стандарте следующим образом:

template <class T, class Allocator = allocator<T> >

class vector {

public:

 …

 template<class InputIterator>

 void insert(iterator position, InputIterator first, InputIterator last);

};

Каждый стандартный контейнер должен поддерживать шаблонную версию интервальной функции

insert
. Аналогичные шаблоны также обязательны для интервальных конструкторов и для интервальной формы
assign
(см. совет 5).

MSVC версий 4-6

К сожалению, в реализации STL, входящей в комплект поставки версий 4-6, шаблоны функций не объявляются. Библиотека изначально разрабатывалась для MSVC версии 4, а этот компилятор, как и большинство компиляторов того времени, не обладал поддержкой шаблонов функций классов. При переходе от MSCV4 к MSVC6 поддержка этих шаблонов была включена в компилятор, но вследствие судебных дел, косвенно затрагивавших фирму Microsoft, библиотека оставалась практически в неизменном состоянии.

Поскольку реализация STL, поставляемая с MSVC4-6, предназначалась для компилятора без поддержки шаблонов функций классов, авторы библиотеки имитировали эти шаблоны и заменили их конкретными функциями, которым при вызове передавались итераторы контейнера соответствующего типа. Например, шаблон

insert
был заменен следующей функцией:

void insert(iterator position, // "iterator" - тип итератора

 iterator first, iterator last); // для конкретного контейнера

Поделиться с друзьями: