Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 141
Текст из файла (страница 141)
И после этаких замеров отбросить лишь эти проверочные фрагменты, причем из наиболее тщательно протестированных участков кода программы, а остальные — оставить. Применение Сйесйеч! лег позволяет выявить многие ошибки. Это не означает, что от них легко избавиться. Редко когда удается написать программу, на !00% устойчивую к операциям +ь, --, *, [), -> и =, потенциально генерирующим исключения. У нас имеются в связи с этим две очевидные стратегии: 1. Перехватывать исключения как можно ближе к местам их возникновения, чтобы обработчик исключения имел неплохой шанс разузнать все о причинах генерации исключения.
2. Перехватывать исключения на верхних уровнях программы и прерывать тем самым работу изрядных кусков программы (оставляя под подозрением все структуры данных, попадающих в указанные части программы). Просто перехватывать исключения, возникшие в неизвестной части программы, и продолжать вычисления в надежде на то, что все структуры данных остались 674 Глава ) 9. Итераторы и аллокаторы в действительных состояниях, безответственно если нет обработки ошибок на более верхних уровнях программы. Простейший пример — финальная проверка результатов вычислений (машиной или человеком). В таких случаях проще и дешевле продолжить работу, чем безнадежно пытаться отловить на нижнем уровне все мыслимые и немыслимые ошибки.
Это упрощение возможно за счет многоуровневой схемы восстановления после возникновения ошибок (914.9). 19.4. Аллокаторы (распределители памяти) Аллокагпоры (айосагогя — распределители памяти) призваны изолировать разработчика алгоритмов и контейнеров, нуждающихся в вьшелении памяти, от низкоуровневых деталей физической организации памяти. Аллокаторы предоставляют стандартные способы выделения и освобождения памяти, а также стандартные имена типов, используемых для указателей и ссылок. Аллокаторы, как и итераторы, суть чистые абстракции. Любой тип, ведущий себя как аллокатор, и есть аллокатор. Стандартная библиотека предоставляет стандартный аллокатор, призванный удовлетворить типичные нужды большинства пользователей.
Но пользователь может разрабатывать и свои собственные аллокаторы, чтобы реализовать альтернативные схемы работы с памятью. Например, речь может идти об аллокаторах, работающих с разделяемой памятью, памятью с автоматической сборкой мусора, памятью на базе заранее выделенного пула объектов (519.4.2) и т.д. Стандартные контейнеры и алгоритмы работают с памятью посредством аллокатора.
Таким образом, предоставляя новый аллокатор, мы предоставляем стандартным контейнерам возможность по-новому работать с памятью. 19.4.1. Стандартный аллокатор Стандартный шаблон айосагог из заголовочного файла <«не«ногу> выделяет память посредством функции орегагог пеи () 56.2.6), и по умолчанию используется всеми стандартными контейнерами: 1е«нр!иге<с!аяя Т> с!тя яИ:: айоеа(ог ( ривйс: (урейеу Т га!ие (уре; (УРЕЙЕУ" Я(ЯЕ 1 Я!ЯЕ 1УРЕ1 (урейеурпя6Я' 1 я(фе«енсе 1урег (урейеу Т" ро!н1е«1 (урег!еГ<оня1 Т" соня! ро!пгег; гурег!е1' Тя ге~егепее ! (урейеу соня! ть сопя! ге/е«енсе! ро!пгег айагеяя(ге~егепее г) оотг (гелин аг) ) сонм ро!н1ег ааагеяя (оотг геГегепее г) оотг (ге1игп яг; ) айосаяог () 1й«он (); 1етр!а1е<е!аяя <(> айосагог(еотгайоеагог<Ю>ь) 1й«оы() -айосаго«() гй«он() ! 675 ) 9.4.
Аппокаторы (распределители памяти) ро!п(ег аИоса(е (з!т (уре п, адоса(ог<юЫ>:: соим ро(п(ег Ып(40) ( Ипалить для и Тз юЫ (Сеадоса(е (рот(ее р, з(се (уре и) (И освобождает память без уничтожя объектов юЫ сопение( (рош(ег р, сопя( Ть га!) (иезг (р) Т (га!) ( ) И инициаля *р зничением чо! юЫ((ез(гоу(ро!и(еер) (р->-Т(); ) Иуничтожоет *р без освобождения памяти з!се (уре так з!се() сопя(йгон () се(ир1асе<с!азз 1(> зсгис( геЬшд ((уре((еуадоса(о(<а> ойег( ) ( И фактически: гуре((еТойосо(ог<((> ойег ): се(ир!а(е<с!азз Т> Ьоо! орега(ог== (соим аИоса(ос< Т>а, соим аИосасог<Т>а ) йюн () (етр!а(е<са(зз Т> Ьоо! орега(ог! = (сопя( аИоса(ог<Т> ь, сопз( адосатг<Т> з) йгозг () Операция аИосасе(и) выделяет память для и объектов, а лля ее освобождения нужно вызвать ИеаИоса(е(р, и) . Заметьте, что (сеаИосасе () также принимает в качестве аргумента число объектов и.
Это позволяет аллокаторам, близким по оптимальности к эффективным, ограничиться хранением минимальной информации о выделяемой имн памяти. С другой стороны, такие аллокаторы требуют от пользователя при вызове ИеаИосасеО всегда предоставлять правильное и. Заметим, что у функции (сеаИоса(е (), в отличие от функции орега(ог Иесесе () (96.2.6), аргумент не может быть равен нулю. Умолчательная реализация класса аИоса(ог использует орегасог пе(г(з!се с) для выделения памяти и орегасог Ие1е(е (юЫ*) для ее освобождения. Это подразумевает, что может быть вызвана ие(г ЬаиИ1ег() и в случае исчерпания памяти может генерироваться исключение ж1:: ЬаИ аИос (96.2.6.2).
Отметим, что аИосасе() не обязана вызывать исключительно низкоуровневые механизмы работы с памятью. Часто аллокатору разумнее хранить список свободных областей памяти, готовых к выделению за минимальное время (919.4.2). Необязательный аргумент Ыис у функции аИосасе() является специфическим для разных реализаций. Например, он полезен для систем, у которых компактность крайне важна. Например, аллокатор может выделять память для связанных объектов в пределах одной и той же страницы в случае страничной организации памяти.
Типом аргумента Ыис служит ройсег из сверхупрощенной специализации: (етр(а(е < > с1озз адоса(о(< юЫ> риЬИс: (урейе! юЫ* рот(ег( (уре((еГсопз( юЫ* сопи! ро(п(ег( У внимание: отсутствует ге!егепсе (уре((ег гоЫ ча1ие (уре( сетр1а(е<с!азз И> з(гис( геыи(с (~ре(сеуаиоса(ог<г(> ойег; ); и фактически: (уре((е~аиосо(ог<((> ойег Тип аИосасог<юЫ>::роси(ее действует как тип универсального указателя и для стандартных аллокаторов есть просто юЫ*. 676 Глава ) 9 Итераторы и аллокаторы Если только в документации на аллокатор не сказано иного, у пользователя есть следующий выбор при вызове айоса(е(): 1.
Не предоставлять аргумент Ып(. 2. Использовать в его качестве указатель на объект, часто применяемый в связи с новым объектом (например, указатель на предыдущий элемент последовательности). Аллокаторы избавляют разработчиков контейнеров от необходимости работать напрямую с «сырой памятью» (га(е тетогу). Для примера рассмотрим, как реализация гес(ог могла бы работать с памятью: (етр!а(е<с(ая Т, с(але А = айоса(ос< Т» с(алл нес(ог ( риЫ1с ( (урейе1(урепате А: (рот(ег дега(от // ... рг!га(е: А аПос; Пега(ог г( П... П обьек(п аллокатора Пукаэатель на элементы риы!с ( ехрйсй нес(ог(л(ге (уре и, сопл( Та га( = Т(), сопяАа а = А () ) : айос(а) ( г = аПос.айова(е(п) ( 1ог(1(ега(огр = г( р<г»п/ »+р) айос.сопягис((р,га1) ( /У ..
) го!а геле(ге (л)хе (уре п) ( (1(и<=сарае!(у() ) (е(игп( Пега(ог р = айос. айова(е (и) Пега(ог о = г; («Ы!е (а<»»л!ге () ) ( айос.соплаис((рь», *а); айос. ((ел(гоу (((»+ ) ( ) /У копируем существующие элементы айос. ((еайоса(е (г, сарасйу () ); П освобождаем старую память г = р — яге() ( У... ) // ... ): Операции аллокатора выражаются в терминах определенных с помощью (уреаеу типов ро(п(ег и геуегепсе, чтобы предоставить пользователю возможность использования альтернативных типов для доступа к памяти. В общем случае зто сделать непро- 19.4, Аллокаторы (распределители памяти) б77 гуреч!еугурепате А:: !етр1а)е геЫпг!<1!пЬ>:: о!Ьег Ь!пЬ аИос; // ")етр!а!е;" слс яС! 3 б Если А — это аллокатор типа аИоса!ог, то тогда геЫпИ<Тлпй>::огйег означает а11осагог<Х!пй>, и рассмотренный оператор ГуреИеУесть просто косвенный способ сказать следующее: яуреае/ адоса!ос<1,тЬ> Ипл аИос! Косвенность в данном случае освобождает нас от необходимости явного упоминания типа аИосагог.
Тип Т.!пй аИос выражается в терминах параметра шаблона А. Например; !етр1аге<с1аяя Т, с1аяя А = аИоса!ог<Т» с)аяя Ига рг)гаге: с1аяя Тляй 1/* ... */); гуре«!еуяурепате А::!етр!а!е геЬ!пч!<Тлпй>:: огйег Ьтл адос! /У адоса!ог<ИпЬ> Тлпд аИос а; А адос! /У... // алло«отар для !ий // алло«атор для 1!я! риЫ1с: гуреч!е/'гурепате А:: ро!п(ег Иегагог! ж...