Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 165
Текст из файла (страница 165)
8064); пз(аггау<4оиЫе> ч4 = чЗ; В двухаргументных конструкторах значение указывается перед числом элементов. Это отличается от порядка следования аргументов для стандартных контейнеров (э]6.3.4). Число элементов в качестве аргумента конструкторов определяет итоговый размер ча!азтау. Большинству программ нужны данные из таблиц или из ввода; это поддерживается конструктором, копируюшим элементы массивов встроенных типов. Например: сопл! ИоиЫе чб(] = (0,1,2,3,4) з сопл( (п! и(] =(0,1,2,3,4) ( ча(аггау<аоиЫе> чЗ (чй, 4); /У 4 элемента: О, 1,2,3 ча(аггау<аоиЫе> ч4(Ы,4); //(уре еггогз и - это не указатель на с(оиЫе ча(аггау<боиЫе> ч5 (чс(, 8); гУ ипбе)]пебз слишком мало элементов для инициализации Эта форма инициализации крайне важна, поскольку вычислительные программы часто выдают данные в виде больших массивов. Тип ча!аггау и вспомогательные средства, связанные с этим типом, разработаны для высокопроизводительных вычислений.
Это отражается в ряде ограничений для пользователей и в определенной свободе для разработчиков, которым разрешено использовать все мыслимые способы оптимизации. Кроме того, операции с ча1аггау можно делать встраиваемыми, они не должны иметь побочных эффектов и не должны иметь синонимов. При сохранении базовой семантики допускаются введение вспомогательных типов и устранение временных объектов.
В итоге, объ- 7В2 Глава 22. Классы для математических вычислений явления в заголовочном файле <га1аггау> могут выглядеть не совсем так, как я представляю их здесь (и в стандарте), но они должны предоставлять те же самые операции с тем же самым смыслом и ожидаемым результатом для любого клиентского кода, не нарушаюшего установленных правил. В частности, элементы массива иа]апву должны обладать обычной семантикой копирования (517.!.4). 22.4.2. Индексирование и присваивание в классе зга!аггау В классе га1аггау операция индексирования применяется как для доступа к отдельным элементам, так и для того, чтобы получать подмассивы: !етр(аге<с1авв Т> с!авв гага««ау риЫ«с: У...
га)аггауь орега!ог= (соап га!аггауь г) га1а«гауь орегагог= (соль! Ть га1); й копирование г У присвоить на! каждому элчпу Т орега!ог[] (в!те г) сопи; Ть орега!о« [1 (вйе 1); га)аггау орега!ог [1 (вйсе) соне!; вйсе аггау<Т> орега!ог[] (вйсе); га1аггау орега«ог [] (соп«48вйсеЬ) сопи; йвйсе аггау<Т> орега!ог[] (сотгйвйсеь) йсм. ~'22.4.б йем. 822.4.8 го!а««ау орегагог[] (сонина!аггау<Ьоо1>ь) сопи! йсм. 822.4.9 «пава агтау<Т> орегагог(] (сопл гагаггау<Ьоо1>ь); га)аггау орега!о«[] (сопвг га!а««ау<в!ге г>ь) сот!; УУсм. 822.4.10 !псе«ее! аггау<Т> орега!ог[] (сои«а га!агтау<пге Г>Ь,); орегагог= (сот! вйсе аггау<Т>ь); прего!ог= (сот! 8вйсе аггау<Т> ь ); ореппог= (сот! «пава аггау<Т>ь); орега!ог= (сот! !пМгес! аггау<Т>ь); га1апауь та!а« ауь та!а««ау ь га1ап ауь й...
): й см. ~22.4.б ,У см. ~22.4.8 У см. 822.4.9 й см. 822.4.10 Массив га1аггау можно присвоить другому массиву этого же типа и размера. С очевидностью «1=«2 копирует каждый элемент «2 в соответствующую позицию массива «1. В случае разных размеров результат такого копирования не определен, а из-за того, что реализация га1аггау сильно оптимизирована по скорости работы, не следует ожидать в этом случае какого-либо информативного исключения или иной разумной формы реакции на ошибку. Дополнительно к рассмотренному общепринятому присваиванию допускается также присваивание, ,скалярной величины. Например, ~7 присваивает каждому элементу г значение 7. Индексация целыми числами вполне традиционна и при этом никакого контроля выхода за допустимые границы индексов не выполняется.
Кроме извлечения индивидуальных элементов операция индексации для гсааггау предоставляет четыре способа извлечения подмассивов Я22.4.6). Операции присваивания (и конструкторы — 522.4.1) принимают такие подмассивы в качестве операн- 22.4. Векторная арифметика 783 22.4.3. функции-члены Для класса ча1аггау определено некоторое количество совершенно очевидных и несколько менее очевидных функций-членов: гетр)ага<с!вяз Т> с1аяя ча!атгау ( риЫ(с: // ...
ча1агтауя орегагог*= (сопя! Та агв) / Уч(!]*=аг8 для каждого элемента //аналогично: /=, ьг=, +=, -=, '=, й=, )=, «ьь и»= // сумма элементов (+= для сложения) // наименьшее значение ( < для сравнения) // наибольшее значение ( < для сравнения) Тяит () соим; Тпип() сопя!1 Ттах() сопл) ча)аи ау яЬ(71 (!п1 !) сопя1; ча!аггау сяЬ((1 (Ы1 1) сопят! //логический сдвиг (влево - ( 0; вправо - 1<0) У Чиклический сдвиг (влево - 1>0; вправо - 1<0) ча1атгау арр)у ( Т]' ( Т) ) сопи; гУ тези!1((] =](ыЯ) для каждого элемента ча)аггау арргу(Т](сопя!Та) ) сопя1; // тези!1((] = -ыД для каждого элемента //аналогичноь +, -, ! // тези(1(!] = )ы(] для каждого элемента ча!аггау орегагог- () соия1; ыа!аггау<Ьоо!> орегагог) () сопя!1 я(ге гя!ге() сопя!; /У число элементов чоЫ гея)ге (я!яе !и, соим Та ча! = Т() ) 1 У п элементов со значением ча1 ): Если я]хе () ==О, то возвраты яат (), ипи () и тпах () не определены.
Далее, если ч — это массив типа ча1аггау, то его можно масштабировать следующим образом: ч*=.2, или ч/=1.3. То есть применение к вектору скаляра означает его применение к каждому элементу вектора. Обычно легче оптимизировать операцию *ьь чем комбинацию отдельных операций * и = 511.3.1). Заметьте, что операции, отличные от присваивания, конструируют новый ча]ап ау. Например: аоиЫе ]пег (йоиЫе г() ( ге!ига Иь1; ) чай!( ( ыа1аггау<аоиЫе> ь ч) ( та!оп ау<доиЫе> ч2 = ч. арр1у (!пег) 1 У получаем инкрементированный ча!оп ау Здесь значение ч не изменяется.
Функция арр1у() не принимает в качестве аргумента 522.9[1)), к сожалению, объекты функциональных классов 518.4). дов. Подходящий набор операций присваивания для типа ча1аггау делает ненужным перед выполнением присваивания преобразование вспомогательных типов, таких как т]се ап ау, в тип ча1аггау. Любая реализация может аналогичным образом определить для типа ча1аггау другие эффективные векторные операции, например, операции ь и *. Наконец, существуют известные приемы оптимизации для векторных операций, включающих срезы (я1)сея) и иные вспомогательные векторные типы. 784 Функции логического и циклического сдвигов, вйг3т() и сэа(![(О, возвращают новый объект типа га1аггау с соответствующим образом сдвинутыми элементами, а исходный гайггау оставляют неизменным.
Например, циклический сдвиг г2=г.сзй(!з(п) породит г2 таким образом, что г2[г) ==о[ ([зп) %г.э[ее() ]. Логический сдвиг гЗ=г. л!зз35((п) породит гЗ таким образом, что гЗ[в] равно в[в+и], если 1з-и — допустимый индекс для г, а в противном случае элемент принимает значение по умолчанию. Считается, что з1з(17() и св!з(!2() осуществляют сдвиг влево, если их аргумент положительный, и сдвиг вправо при отрицательном аргументе. Например: го!8 1'( ) ( гп! а!рва [ ] = (1, 2, 3, 4, 5, 6, 7, 8); Для массивов га1аггау операции» и «являются операциями битовых сдвигов, но не операциями сдвига в элементах массива и не операциями ввода/вывода [э22.4.4).
Для выполнения битовых сдвигов в элементах интегрального типа массива га!аггау можно использовать «= и»кч Например: гоИ! ( га(атау<!пг> и, га!аггау<йоиЫе> гг[) ( г1 «= 2з гй «= 2) ) // ч!Я«=2 для всех элементов и' //еггог< сдвиг не определен для значений с плавающей запятой Размеры массивов га1аггау изменять можно. Однако гел!ге () — это не та операция, что превращает га1аггау в структуру, способную динамически расти как гесгог или лзг!п8.
Вместо этого, гав!хе ( ) реиниц пал изирует массив, заменяя текущее содержимое умолчательными значениями. Старое содержимое при этом теряется. Часто массив га1аггау становится после выполнения операции гел!ге() тем, что создается как пустой вектор. Рассмотрим, как мы могли бы инициализировать га1аггау из ввода: юЫ!'() ( зпгп=О; с1п» и; / читаем размер массива [!(и<=0) епог (" неверные границы массива" ); га1аггау<доиЫе> г (и); 1п! ! = О; тйте [!<п ьь с[п»г[1з-+] ); //зополняем массив Ц'(1(=п) етог ( "введено слишком мало элементов" ); // создаем массив нужного размера га1аггау<1пс> га1аггау<ии> гагаг ау<на> гагаггау<(п!> га!аггау<!пс> га!аг ау< [пг> га!аггау<(пг> г (а!рва, 8); г2 = г.эйли)(2); г3 = у«2; г4 = г.
заф(-2); г5 = г»2; гб = г.сейф(2); г7 = г. сэйл(-2); Глава 22. Классы для математических вычислений //1,2,3,4,5,6,7,8 // 3,4,5,6, 7,8,0,0 //4,8,12,!6,2024,28,32 // 0,0,1,2,3,4,5,6 // 00, 0,1, 1, 1,1,2 // 3,4,5,6, 7,8, 1,2 // 78,1,2,3,4,5,6 22 4 Векторная арифметика 785 Если ввод нужно обрабатывать в отдельной функции, можно поступить так: юЫ тЫа!яе (гот !при! (га(аг«ау<доиЫе>ь г) (пги = О! сЫ»и! У читаем размер массива (1(и<=0) ею о« ( ч неверные границы массива" ); г.«ез!ье(и); 1пг г = д! юЫ(е(1<п ьь с]п»«[!+в] ) ! о'заполняем массив (Г(1! =п) е««ог ("введено слишком мало элементов" ) ! ) У задаем г правильный размер гоЫО() ( ва1аггау<ИоиЫе> г! !тдайхе 1«от (при! (в) ! У..