Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - [21]

Шрифт
Интервал

, в предположении, что имеет место именно такая реализация >std::vector::reference.

Вызов >features возвращает временный объект >std::vector. Этот объект не имеет имени, но для упрощения нашего рассмотрения я буду называть его >temp. Для >temp вызывается >operator[], в результате чего возвращается объект >std::vector::reference, содержащий указатель на слово в структуре данных, хранящей интересующий нас бит (эта структура находится под управлением >temp), плюс смещение в слове, соответствующее пятому биту. Переменная >highPriority представляет собой копию этого объекта >std::vector::reference, так что >highPriority тоже содержит указатель на слово в >temp плюс смещение, соответствующее пятому биту. В конце инструкции объект >temp уничтожается, так как это объект временный. В результате переменная >highPriority содержит висячий указатель, что и дает неопределенное поведение при вызове >processWidget:

>processWidget(w, highPriority); // Неопределенное поведение!

>                                // highPriority содержит

>                                // висячий указатель!

Класс >std::vector::reference является примером прокси-класса (proxy class), т.e. класса, цель которого — эмуляция и дополнение поведения некоторого другого типа. Прокси-классы применяются для множества разных целей. Например, >std::vector::reference нужен для того, чтобы создать иллюзию, что >operator[] класса >std::vector возвращает ссылку на бит, а интеллектуальные указатели стандартной библиотеки (см. главу 4, “Интеллектуальные указатели”) являются прокси-классами, которые добавляют к обычным указателям управление ресурсами. Полезность прокси-классов — давно установленный и не вызывающий сомнения факт. Фактически шаблон проектирования “Прокси” — один из наиболее давних членов пантеона шаблонов проектирования программного обеспечения.

Одни прокси-классы спроектированы так, чтобы быть очевидными для клиентов. Это, например, такие классы, как >std::shared_ptr и >std::unique_ptr. Другие прокси-классы спроектированы для более-менее невидимой работы. Примером такого “невидимого” прокси-класса является >std::vector::reference, как и его собрат >std::bitset::reference из класса >std::bitset.

В этом же лагере находятся и некоторые классы библиотек С++, применяющих технологию, известную как шаблоны выражений (expression templates). Такие библиотеки изначально разрабатывались для повышения эффективности кода для числовых вычислений. Например, для заданного класса >Matrix и объектов >m1, >m2, >m3 и >m4 класса >Matrix, выражение

>Matrix sum = m1 + m2 + m3 + m4;

может быть вычислено более эффективно, если >operator+ для объектов >Matrix возвращает не сам результат, а его прокси-класс. Иначе говоря, >operator+ для двух объектов >Matrix должен возвращать объект прокси-класса, такого как >Sum, а не объект >Matrix. Как и в случае с >std::vector::reference и >bool, должно иметься неявное преобразование из прокси-класса в >Matrix, которое позволит инициализировать >sum прокси-объектом, полученным из выражения справа от знака “>=”. (Тип этого объекта будет традиционно кодировать все выражение инициализации, т.e. быть чем-то наподобие >Sum, Matrix>, Matrix>. Определенно, это тип, от которого следует защитить клиентов.)

В качестве общего правила “невидимые” прокси-классы не умеют хорошо работать вместе с >auto. Для объектов таких классов зачастую не предусматривается существование более длительное, чем одна инструкция, так что создание переменных таких типов, как правило, нарушает фундаментальные предположения проекта библиотеки. Это справедливо для >std::vector::reference, и мы видели, как нарушение предположений ведет к неопределенному поведению.

Следовательно, надо избегать кода следующего вида:

>auto someVar = выражение с типом "невидимого" прокси-класса;

Но как распознать, когда используется прокси-объект? Программное обеспечение, использующее невидимый прокси, вряд ли станет его рекламировать. Ведь эти прокси-объекты должны быть невидимыми, по крайней мере концептуально! И если вы обнаружите их, то действительно ли следует отказываться от >auto и массы преимуществ, продемонстрированных для него в разделе 2.1?

Давайте сначала зададимся вопросом, как найти прокси. Хотя “невидимые” прокси-классы спроектированы таким образом, чтобы при повседневном применении “летать вне досягаемости радара программиста”, использующие их библиотеки часто документируют такое применение. Чем лучше вы знакомы с основными проектными решениями используемых вами библиотек, тем менее вероятно, что вы пропустите такой прокси незамеченным.

Там, где документация слишком краткая, на помощь могут прийти заголовочные файлы. Возможность сокрытия прокси-объектов в исходном коде достаточно редка. Обычно прокси-объекты возвращаются из функций, которые вызываются клиентами, так что сигнатуры этих функций отражают существование прокси-объектов. Например, вот как выглядит >std::vector::operator[]:

>namespace std { // Из стандарта С++


>template


Еще от автора Скотт Мейерс
Эффективное использование STL

В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


Как функции, не являющиеся методами, улучшают инкапсуляцию

Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Платформа J2Me

Эта книга научит вас, как разрабатывать программное обеспечение для платформы J2ME компании «Sun Microsystems». Эта книга придерживается стиля учебного пособия, это не справочное руководство.Цель — дать вам твердую основу в понятиях и техниках, которая даст вам возможность решиться на самостоятельную разработку качественных приложений.


Виртуальная библиотека Delphi

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


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

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


Программное обеспечение встроенных систем. Общие требования к разработке и документированию

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.