Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 31
Текст из файла (страница 31)
Впрочем, на многих машинах и здесь достигается повышение эффективности за счет помещения массивов констант в специальную область памяти только для чтения. Типичным является использование констант в качестве размера массивов и меток в инструкции саяе. Например: Глава 5. Указатели, массивы и структуры соилг сп1 так = 128, гпг о [тих), оо1с(/(1гг1 г) ( ьшасЬ (1) ( сале а // саяе Ь // ) ) 5.4.1. Указатели и константы В операциях с указателями участвуют два объекта: сам указатель и объект, на который он ссылается.
Помещение ключевого слова соия1 перед об ьявлением указателя делает константой объект, а не указатель. Для обьявления самого указателя в качестве константы, используется оператор объявления *соия1, а не просто *. Например: иоЫ/г (сдаг*р) ( сдаг лЦ вЂ” 'богт", //укиэатель на конспшнти // ошибкш рс указывает но конситнпгу // правильно // констинтныб указатель // правильно //ошибка срявляется константоа О констонгиньш указатель на консгианту //ошибка: срг укаэьгвает на константу //огиибка: сргявляется констонтои сопя1сйаг*рс= я, Рс[3) = '8', рс=р, сдаг*сопл1 ср = л, ар[8) = 'а', ср=р, сопи сдаг 'сопя1срс = я, срс[З] = 'а', срс=р, В таких ситуациях альтернативой константам часто выступают пере пкления (5 йг.8).
То, каким образом солИ можно использовать с функциямп, являющимися членами классов, обсуждается в у 10.2,6 н у 10.2.7. Для избежания ямагических чисел» в коде следует систематически пользоваться символическими константами, Еслн некое число, такое как размер массива, регулярно повторяется в коде, модифицировать кол будет сложно, потому что придется найти и изменить каждое вхожденце данного числа. Использовапне символической константы локализует информацию. Обычно численные константы означают некоторые предположения о программе. Например, 4 може~ означать количество байт, требуемых для представления целого, 128 — объем буфера ввода, а 8.24 — курс датской кроны по отношению к доллару США.
Тому, кто сопровождает программу, трудно будет понять смысл этих чисел, если онн будут записаны в виде числовых констант. Часто на такие числа пе обращают внимания при переносе в другую среду или прн внесении изменений, что приводит к ошибкам. Представляя такие значения в виде ясно комментированных символических констант, вы сводите к минимуму упомянутые проблемы сопровождения. 157 5.5. Ссылки Оператор объявления, который делает указателысонстантой, — эго *сопя!. Нет оператора объявления соле!*, поэтому ключевое слово сопя! слева от * интерпретируется $ как часть базового типа. Например: // констангиньгд указатель на суаг // указагпель но коншгонту гпипп гдаг // указатель на консгпиюлу типа спаг с!гаг*сопз1ср; с!гаг соле рс; солз1 с!гаГ" рс2; Некоторые люди читают такие объявления справа налево, Например, «ср является константным указателем на сйаг», а «рс2 является указателем на константу типа с/заг».
Некоторый объект при обращении к нему через один указатель может быть константой, а при обращении через другой — переменной. Это свойство особенно полезно для аргументов функций. Объявив аргумент-указатель константой, функция не сможет изменить объект, на которгягй он ссылается. Например: с!гас* зггсру ~с!гаг"р, сопзг с!гаг' д~, //нельзя излгенггть 'д Вы можете присвоить адрес переменной указателкг на константу, потому что это безвредная операция.
Нельзя, однако, присвоить адрес консганты произвольному указателю, потолгу что в этом случае можно будет изменить значение объекта, Например: ооиЦ4 (] Г! рн помощи явного преобразования типа можно устранить ограничение, состоящее в том, что указатель указывает на константу Я ! 0,2.7.1 и э 15А.2.1). 5.5. Ссылки Ссылка (ге1егепсе) является альтернативным именем объекта. Ссылки чаще всего используются для указания аргументов функций и возвращаемых значений вообще, и прп перегрузке операторов в частности 1глава 11).
Записью означает ссылку на Х. Например: // г и г ссылаются на одно и то же целое //х= ! г=2, 0г'=2 Чтобы быть уверенными, ггто ссылка является именем чего-либо (то есть, привязана к обьскту), мы должны инициализировать ее. Например: ш1 а = 1, соп в1 1лг с = 2; солз1 1л1" р1 = с.сг солз1 !п1* р2 = за, ш1' рд = !.с ру = 7, оо1агД гп1г'=1; 1лЖг=1; ш1х= г; // привильно // правильно //оигггбка; инициализация гп1'значенггелг тигт сопзгшг* // попытка ггзлгенггть зничение констанпгыг с Глава 5.
Указатели, массивы и структуры 138 к'п1 к' = 1; кпЯг! =к; Ягг; ехкегп кпЯ гЗ; // правильна — г1 инициализнровани // ошибка: отсутсптуепк ккницккализакпар // кравильно — гЗ пни циализирована в друеалк шесте Иницклализацпя ссылки кардинально отличается от присваивания ей значения, Несмотря на форму записи, пи одклн оператор не выполняет действий над ссылкой. Например: иоЫу(1 | 1п111 = 0; клЯп =и'; гг««; ии* рр = с.гг; 0 и увеличена на 1 //рр укизываепк на и' Выражение ггь+ допустимо, но не увеличивает ссылку гг, ++ применяется к целому значению 11. Как следствие, значение ссылки нельзя изменить после инициализации.
Она всегда ссылается на обьект, которым инициализирована. Чтобы по.лучить указатель на объект, именем которого является ссылка гг, мы можем написать с гг. Очевидной реализацией ссылки является (коккстантныйк) указатель, при каждом использовании которого происходит разыменование. Г>ольщого вреда в такой интерпретации ссылки нет, но при этом надо помнить, что ссы.лка, в отличие от указателя, не является объектом, над которым можно выполнять операции: // ошибки: требуетсл 1са1кке // правильна к1аккЫеу акг = 1; сопле к)аиЫез, ск/г= 1; Можно пропнтерпрстировать последнюю инициализацию следующим образом: // создать врененную перененную // с соитветскпвуюи|ил зна кенккелк // затеи использовать врез кенную // перел енну ко кап инициал ива клар сд» к)оиЫе 1етр = к)оиЫе 111, санек к1аиЫей сдг = 1етр; Временная переменная, созданная для хранения инициализатора, существует до конца области видимости иннциализирусмой ею ссылки, В некоторых случаях компилятор может оптимизировать ссылку таким образом, что во время исполнения вообще не будет существует обьекта, представляющего ссылку.
Инициализация ссылки тривиальна, кокда иннцналпзнтором является !к а1це (объеккц адрес которого можно получить; см. у Гк,9.6). Иннцнализатором для «просто» Тй должно быть |уа1це типа Т. Иннциалнзатор для сопз1 ТЯ не обязан быть |уа1це и даже иметь тип Т. В таких случаях: |1) если необходимо, осуществляется неявное преобразование к типу Т(ськ. у В.б); |2~ результирующее значение помещается во временную переменную типа Т; |31 временная переменная используется как значение иницнализатора. Рассмотрим пример: 139 5.5. С с ыл ки Ссылки на переменные и ссылки на константы различаются: создание временной переменной в случае ссылки на переменную интенсивно провоцирует ошибки. Присваивание переменной сводится к присвацваиию (скоро псчезаюшей) временной переменной. Подобных проблем не существует со ссылками на константы. Ссылки на константы часто находят применение в качестве аргументов функций (() 11.6). Ссылка может использоваться в качестве аргумента функции, которая изменяет значение передаваемого ей ооъекта.
Например: ио!г! ясгетеп1 (!л1Й аа) ( ааль, ) оо!!!Я) ( сп1х=1, !лсгетепг (х), ) !г/л = г Семанпп;а передачи аргументов тождествена семантике инициализации, поэтому после вызова сасгетел1его аргумент аа становится другим именем для х. Чтобы программа была читаемой, как правило стоит избегать функций, изменяющих свои аргументы. Предпочтительнее явно возвратить значение функции или запросить указатель в качестве аргумента: т1пех1 (!и! р) ( ге1игп рч1,) ио!с! !и ст (!л ~' р) (("р)++, ) ио!!! д () ( со! х= 1, слсгетел1 (х), х = лех1 (х), !пег (Вх), Ох=г Дх=з !/х=4 е!гис1 Раи ( е!г!лд лате, г)оиЫе иа1, ), Идея состоит в том.
что у строковой переменной есть связанное с ней значение с плава- ющей точкой. Нес.ложно определить функцию ва(ие (), которая поддерживает структу- ру данных, с остояп1ую из одной пары (Ра! г) для каждой строки, переданной фупкппп. Для краткости можно написать очень простую (и неэффективную) реализацию: По форме записи !лсге>пел1 (х) нельзя догадаться, что значение х может быть изменено, в отли ше от х=лех1 (х) и !лег (8х). Соответственно, «простой.
ссылочпый аргумент следует использовать только тогда, когда имя функции прозрачно намекает на изменение ею ссылочного аргумента. Ссылки также применяются для написания функций, которые можно использовать н в левой, и в правой частях присваивания. Многие пз самых любопытных случаев гакого применения обнаруживаются в нетривиальных типах, определяемых пользователем. В качестве примера определим простой ассоциатнвнгяй массив. Сначала определим структуру для пар (пыя, значение) Ра!г следу!ошпы образом: 140 Глава 5. Указатели, массивы и структуры оес1ог<Расг> ра!гз, с!оиЬ!ей оа1ие )сопз1 з1г!пяй з) поддерлсивоет набор пар Ра!г: ии)ет строку з; если найдена, возвращает соответствующее значение; иване создает новую пару и возвращает знанение по уиолканто О рог )т1 !=О; ! расгззсее )); гн-) Ц )з == ра!гзЯ пате) ге1игл раи зЯ.оа1; Ра!г р = ( з, О ), расгзризЬ Ьасй(о); 11'добавите лару вконец (3" 3.73) ге1игп ра!гз(раггз.згге )) — Р та!, Эту функцию можно интерпретировать как массив чисел, пропндексированный строкой символов, Для заданного строкового аргумента оа1ие () находит соответствуюп1ий числовой объект (а не значение соответствующего числового объекта), а затем возврап!ает ссылку ца него.
Например; 1'1' соснитать количество вхозкдений ко зсдого слове~ во вкоднон потоке !иста!п )) ( згг)по Ьи(,. и6!)е )с!п»Ьи)) ии!ие )ЬиЯ+->; )ог )иес1ог<ра!г> соле! !1ега1огр = ра!гз.Ьея!и )), ршра!гз епд )); ++р,' сои1 «р — >лате « '. ' «р->оа! « '~л'; В цикле шй!!е при чтении каждого слова из стандартного по~ока ввода ссл в строку ЬиУ (й 3.6) модифицируется соответствующий счетчик. В конце печатается результирующая таблица слов с числом их вхождений.