Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 145
Текст из файла (страница 145)
всех символов из я Каждый шсйаг 1в шя инициализируется соответствующим сйагиз я. Символы нумеруются начиная с О, так что строка — это последовательность символов с номерами от О до 1еп016 ()-1. Длина строки 1еп82Ь () — это просто синоним я(ге (); обе функции возвращают число символов в строке.
Отметим, что вычисление длины строки не основывается на понятии «завершающего нуля», обрывающего С-строку(2 20А.1). Реализация Ьаясс я1плд хранит длину строки, не полагаясь ца завершающий символ [ноль). Подстроки выражаются как позипия символа плюс число символов. По умолчанию значение проз инициализируется максимальным возможным числом, означая как бы «все элементы».
Для создания строки из и неопределенных символов конструктора не существует. Самое большое, что мы можем сделать, чтобы к этому приблизиться, — это предоставить конструктор, который производит и копий указанного символа. Отсутствие конструктора, принимающего только один символ, и конструктора, принимающего только некоторое количество элементов, позволяет компилятору обнаружить ошибки вроде определений я2 и яЗ в приведенном выше примере.
Копиру1ощий конструктор — это конструктор с четырьмя аргументами. Три из них имеют значения по умолчанию. Ради эффективности этот конструктор можно реализовать как два отдельных конструктора. Пользователь не сможет узнать об этом, не посмотрев сгенерированный код. Конструктор, являющийся членом шаблона, — самый универсальный. Он позволяет инициализировать строку значениями из произвольной последовательности. В частности, он позволяет инициализировать строку элементами разных символьных типов, если для них существует преобразование, Например: 653 '20.3. Тип (эаэ(с э1г>по 20.3.5.
Ошибки Часто строки просто считывают, записывают, распечатывают, хранят, копируют и т. д. Это не вызывает проблем нли, в худшем случае, возника>от проблемы, связанные с быстродействием. Однако когда мы начинаем манипулировать отде.льными подстроками и символами, чтобы составить новую строку из существующих, то рано или поздно делаем ошибки и можем произвести запись за конец строки.
Чтобы сделать доступ к отдель ному символу явным, функция а1 (( проверяет диапазонн и, если мы пытаемся обратиться за конец строки, генерирует исключение ои1 о) гпешогу; П не делает этого. Большинство операций со строками принимают позицию символа и число символов. Если позиция больше размера строки, генерируется исключение ои1 о/" галде. «Слишком болыпое» число символов воспринимается просто как «все остальные символы». Например: ооиЩ ( з1гтуз ='Бпобо14', зггту з2 (з, 100, 2(; О позиция сю>вола за пределал>и строка: //сгенерируеп>ся ои1 о/ гапуе //кисло символов кслшиком велико>: //рпвносильно яЗ(я, 2, з.заве() — 2) ,Г/ символы, наминал с з[2( згг(аузЗ (з, 2, 100(; згг1пуз4 (з, 2, згг1пуспроз>; Таким образом, «слишком больших» позиций следует избегать, по «слишком большие» числа символов могут пригодиться.
Фактически, проз является максимально возможным значением для я(яе 1уре. Мгл можем попытаться указать отрицательную позицию или отрицательное число символов: оой1 у(з1ппуз з( ( з1гтузб (я, — 2, 3(, з1г1пузб (з, 3, — 2(; //болыиая позиция! Сгенерируе>пся ои1 ог саиде //болыиов кисло символов! Правильно Однако з(ае 1уре, используемый для представления позиции и числа символов, имеет тип ипз(упе>1, поэтому отрицательное число является просто запутанным способом обозначить большое положительное Я 16.3.4).
Отметим, что функции для поиска подстрок Я 20.3.11), если ничего не нашли, возвращают прая. То есть они не возбуждают исключений. Олнако при последующем использовании проз в качестве позиции символа исключение возбудится. Другой способ обозначить подстроку — пара итераторов. Первый итератор определяет позицию, а разность между двумя итераторами — число символов. Как обычно, нтераторы не производят проверки диапазона. При использовании С-строк проверка диапазона труднее. Когда в качестве аргумента используется С-строка (указатель на айаг), функции нз Ьаз(с з1г(пд считают, что указатель не равен О. Получая позицию символа для С-строк, они считают эту строку достаточно длинной, чтобы позиция оказалась в ее пределах. Соблюдайте Глава 20.
Строки 554 ьгнпуь (я!г!пу:проз, 'а'); //воябудится 1епу1Ь еггог!) 20.3.Б. Присвпивание Гстественно, для строк определены операции присваивания: 1етр1а1е<с!аз« СЬ, с!аз« Тг = сваг 1га!!«<СЬх, с1аяя А = аПоса1ог<СЬ» с1аяь Ьа«Ы «!ггпу( риЬИс. 0" // присваивание !немного похоже на оес1ог и Ь«1: ф 1Г>3А): Ьазсс я1г!пуйорегагог= (соп«1Ьаз>с ягппуй«1>); Ьоя!с я!г!пдй орега1ог= (соп«1СЬ*р); Ьаз!с яггтуйорега1ог —. (СЬ с); Ьатс «1г!пуй аяя!уп (соль! Ьая!с «1г!пуй[ Ьая!с я!гшуй аз«!уп (соп«1Ьа«1с «1г!пуйя, я!ее 1уре роя,«1ье !урви), Ьая!с «1гй>уйаяз!уи (сопягСЬ'р, я!ье гуре п); Ьаягс з1г!пуй азя!дп (соп«1СЬ* р); Ьаз!с я!ггпуй из«пуп (я!ее 1уре и, СЬ с); 1етр1пге<с1аяя 1пь Ьаягс «!г!пуй ая«1уп (1пЯг«1 1п 1аяг); Как и другие стандартные контейнеры, строки имеют семантику значений.
То есть когдаоднойстрокеприсваиваетсядругая,присваиваемая строкакопируется,ипослеприсваивания существует две отдельных строки с одинаковыми значениями. Например: ооЫд () ( я1г!пу«1 = 'КпоЫ"; «!ггпу«2 ="То!2 // две копии "го1' //«2 стала "Ти1, «1 по-пре>хнелу "То1' «1=«2; з2[1) = 'и'; ) Присваивание строке одного символа поддерживается, несмотря на то, что инипиа- лизации с одним символом не существует: оой! Т() ( // отибно: ини>(иолиьаиия типо>> слог // правильно> зто присваивания згг(пд з = 'а'; з ='а'; з='а; ь=я; осторожность! Здесь нужна параноидальная осторожность за исключением случаев, когда использу>отея символьные литералы.
Для всех строк выполняется неравенство (епй2Ь () < прож В некоторых случаях, таких как вставка одной строки в другую (9 20.3,9), может (хотя зто и маловероятно) получиться строка слишком длинная, чтобы ее представить. В этом случае сгснерируется [ела еггог. Например; 655 20.3. Тип Ьасйо я1ппо 20.3.7. Преобразование в С-строку Как показано в 9 20.3.4, строку я!г!пу можно инициализировать С-строкой, а С-стро- ки можно присваивать строкам я!г!пд. И наоборот, копию символов из я1г!пд можно поместить в массив: 1етр!а!в<с!аяя СЬ, с!аяя Тг = сЬаг !га!1якСЬ>, с!аяя А = а!!оса1огкСЬ» с)аяя Ьая!с яггспу( риЫ1с: //...
// преобразование в С-строку сопя! СЬ' с ягг () сопя!, сопя! СЬ' с!ага () сопя!; я!ее туре сору (СЬ'р, яссе 1уре и, ясее гуре роя = О) сопя!, Функция с)а!а () пишет символы строки в массив и возвращает указатель на него, Массив принадлежит я!г!пд, и пользователь не должен пытаться его уничтожить. Также пользователь не может пола~аться на его значение после вызова неконстантной функции над этой строкой. Функция с я1г() похожа на с(а!а () но добавляет в конец !), традиционно обрываюгцнй С-строку.
Например: воЫХ() ( // ! !) !) =12 // ! зываетна)дсии // плохо: не хватает конца строки //ошибка: р! указывает на константный лшсоав я)г!пуя = "равноденствие", сопя! сЬаг' р) = я.аа1а (); рейну" ("р! .= %я', и', р1); р1[2) = 'а'; я[2) = 'а'; сЬаг с = р1[1); //плохо вызов я да!а!)гюслв излгенения я //р2указывает на 14 спиволов //правильно; с яп!) добавила // завсршаюгцш) символ сопягсЬаг" р2 =яс ягг (), ргспУ ("р2 = %я~а', р2'„ Возможность присвоить строке символ сЬаг не очень полезна и даже может рассматриваться как провоцирующая на ошибки, однако приписывание сйаг в конец при помощи оператора+= порой важно Я 20.3.9), и было бы странно, если бы могли написать я+='с', а я я+'с' было бы незаконно. Имя аяя!дп () используется для присваиваний, которые являются альтернативами конструкторов со многими аргументами (5 15.3.4, з 20.3А). Как упоминалось в 9 11.12, я!г!пд можно оптимнаировать, чтобы на самом деле копирования не производилось, если только не нужны две копии какой-либо строки.