Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 [ 50 ] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

Однако кроме этого случая, запись const в примере 24-2 не является оптимизацией для большинства классов z, а там, где это все же приводит к оптимизации, - это уже не оптимизация генерации объектного кода компилятором.

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

В общем случае компилятор не может использовать константность параметров для устранения создания копии аргумента или предполагать побитовую константность Как уже упоминалось, имеется слишком много ситуаций, когда данные предположения оказываются неверными. В частности, Z может иметь члены, описанные как mu-tablе, или где-го (в самой функции f, в некоторой другой функции или в непосредственном или косвенном вызове функции-члена z) может быть выполнено приведение типов const cast или использованы какие-то другие трюки.

Имеется один случай, когда компилятор способен сгенерировать улучшенный код, если:

• определения копирующего конструктора Z и всех функций Z, прямо или косвенно использующихся в теле функции f, видимы в данной точке;

• эти функции достаточно просты и не имеют побочного действия;

• компилятор имеет агрессивный оптимизатор.

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

В качестве отступления стоит упомянуть об одной детали. Некоторые профаммисты утверждают, что есть еще один случай, когда компилятор может генерировать лучший код на основании const, а именно - при выполнении глобальной оптимизации. Дело в том, что это утверждение остается верным и в том случае, если убрать из него упоминание const. Не важно, что глобальная оптимизация все еще весьма редка и дорога; настоящая проблема заключается в том, что глобальная оптимизация использует всю имеющуюся информацию об объекте, в том числе о его реальном использовании, так что такая оптимизация работает одинаково независимо от того, объявлен ли объект как const или нет - решение принимается на основании того, что в действительности происходит с объектом, а не того, что обещает профаммист. Так что и в этом случае применение ключевого слова const ничего не дает в плане оптимизации генерируемого кода.

Заметим, что несколькими абзацами ранее я сказал, что "запись const в примере 24-2 не является оптимизацией для большинства классов Z" и для "генерации объектного кода компилятором". В оптимизаторе компилятора имеется гораздо больше возможностей, чем кажется, и в некоторых случаях const может быть полезен для некоторой реальной оптимизации.

б) Говорим ли мы об оптимизации компилятором или о некотором другом типе оптимизации при условиях, рассмотренных в пункте а)? Поясните свой ответ.

Например, автор Z может выполнять некоторые действия с константным объектом по-другому, написав более эффективную версию функции для случая с константным объектом.

Пусть в примере 24-2 z - класс "handle/body", такой как класс string с использованием подсчета ссылок для выполнения отложенного копирования.



пример 24-3

void f( const Stri ng s ) {

s[4]; или использование итераторов

Для данного класса String известно, что вызов оператора operator[] для константного объекта string не должен приводить к изменению содержимого строки, так что можно предоставить константную перегрузку оператора operator[], которая возвращает значение типа char вместо ссылки char&:

class string {

... public:

const char operator

char& operator

...

( size t ) const; ( size t );

Аналогично, класс String может предоставить вариант итератора consti terator, оператор operator* для которого возвращает значение типа char, а не char&.

Если выполнить описанные действия и после этого воспользоваться оператором operator[] или итераторами, а переданный по значению аргумент объявлен как const, то тогда - чудо из чудес! - класс string без какой-либо дополнительной помощи, автоматически :) оптимизирует ваш код, устранив глубокое копирование...

в) В чем состоит лучший путь достижения того же эффекта?

...но того же эффекта можно достичь, просто передавая аргумент по ссылке.

Пример 24-4: более простой способ

void f( const z& 2 ) {

...

Этот способ работает независимо от того, использует ли объект идиому ban-ё1еД)оёу или подсчет ссылок или нет, так что просто воспользуйтесь им!

> Рекомендация

Избегайте передачи параметров как константных значений. Предпочтительно передавать их как ссылки на константные объекты, кроме тех случаев, когда это простые объекты наподобие int, с мизерными затратами на копирование.

Резюме

Вера в то, что ключевое слово const помогает компилятору генерировать более качественный код, очень распространена. Да, const действительно хорошая вещь, но основная цель данной задачи - показать, что предназначено это кгиочевое слово в первую очередь для человека, а не для компиляторов или оптимизаторов..

Когда речь идет о написании безопасного кода, const - отличный инструмент, который позволяет программистам писать более безопасный код с дополнительными проверками компилятором. Но когда речь идет об оптимизации, то const остается в принципе полезным инструментом, поскольку позволяет проектировщикам классов лучше выполнять оптимизацию вручную; но генерировать лучший код компиляторам оно помогает в гораздо меньшей степени.

Задача 24. Константная оптимизация 1 67



Задача 25. inline Сложность: 7

Быстро ответьте: когда выполняется встраивание? И можно ли написать функцию, которая гарантированно никогда не окажется встраиваемой? В этой задаче мы рассмотрим много различных случаев встраивания, причем некоторые из них вас удивят.

Вопрос для новичка

1. Что такое встраивание (inlining)?

Вопрос для профессионала

2. Когда выполняется встраивание? Может ли оно выполняться:

а) во время написания исходного текста?

б) во время компиляции?

в) во время компоновки?

г) при инсталляции приложения?

д) в процессе работы?

е) в некоторое другое время?

3. Дополнительный вопрос: какого рода функции гарантированно не будут встраиваемыми?

Решение

Какой ответ выберете вы на второй вопрос? Если вы выберете ответы а) или б), то вы не одиноки. -Это наиболее распространенные ответы на данный вопрос, и в книге [Sutter02] я уже вкратце обращался к этой теме. Но если бы тема этим и исчерпывалась, то мы могли бы на этом завершить рассмотрение задачи и отправиться на пикник. Но на этот раз пикника не будет. У настоящего мужчины всегда найдется что сказать. Причем сказать можно достаточно много.

Причина появления данной задачи в книге - стремление показать, почему наиболее точный ответ на главный вопрос задачи - любой из перечисленных, а на последний - "никакие". Непонятно, почему? Тогда читайте дальше.

Краткий обзор

1. Что такое встраивание (inlining)?

Если вы читали [Sutter02], то вы можете пропустить этот и несколько следующих подразделов и перейти сразу к разделу "Ответ В: во время компоновки" на стр. 171.

Коротко говоря, встраиваемость означает замену вызова функции подстановкой копии ее тела. Рассмотрим, например, следующий исходный текст.

пример 25-1

double sguareC double х ) { return х * х; } int main С) {

double d = SquareC 3.14159 * 2.71828 );

Идея встраиваемости вызова функции (как минимум, концептуально) заключается в том, что программа преобразуется так, как если бы она была написана следующим образом.

Задача 7.1 в русском издании книги. - Прим. ред. 168 Оптимизация и эффективность



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 [ 50 ] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85