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

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

Что касается С++11, то в клуб специальных функций-членов приняты два новых игрока: перемещающий конструктор и оператор перемещающего присваивания. Их сигнатуры имеют следующий вид:

>class Widget {

>public:

> …

> Widget(Widget&& rhs);            // Перемещающий конструктор

> Widget& operator=(Widget&& rhs); // Оператор перемещающего

>                                  // присваивания

>};

Правила, регулирующие их создание и поведение, аналогичны правилам для их копирующих двойников. Перемещающие операции генерируются только если они необходимы, и если они генерируются, то выполняют “почленное перемещение” нестатических членов-данных класса. Это означает, что перемещающий конструктор создает каждый нестатический член-данные класса из соответствующего члена его параметра >rhs с помощью перемещения, а оператор перемещающего присваивания выполняет перемещающее присваивание каждого нестатического члена-данных из переданного ему параметра. Перемещающий конструктор также выполняет перемещающее конструирование частей базового класса (если таковые имеются), а оператор перемещающего присваивания выполняет соответственно перемещающее присваивание частей базового класса.

Когда я говорю о перемещающей операции над членом-данными или базовым классом, нет никакой гарантии, что перемещение в действительности имеет место. “Почленные перемещения” в действительности представляют собой запросы на почленное перемещение, поскольку типы, которые не могут быть перемещены (т.e. не обладают поддержкой операций перемещения; например, таковыми являются большинство старых классов С++98), будут “перемещены” с помощью операций копирования. Сердцем каждого почленного “перемещения” является применение >std::move к объекту, из которого выполняется перемещение, а результат используется в процессе разрешения перегрузки функций для выяснения, должно ли выполняться перемещение или копирование. Этот процесс детально описывается в разделе 5.1. В этом разделе просто помните, что почленное перемещение состоит из операций перемещения для тех членов-данных и базовых классов, которые поддерживают перемещающие операции, и из операций копирования для тех, которые перемещающие операции не поддерживают.

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

Две копирующие операции независимы одна от другой: объявление одной не препятствует компилятору генерировать другую. Так что если вы объявляете копирующий конструктор, но не копирующий оператор присваивания, а затем пишете код, которому требуется копирующее присваивание, то компиляторы будут генерировать оператор копирующего присваивания вместо вас. Аналогично, если вы объявили оператор копирующего присваивания, но не копирующий конструктор, а вашему коду нужен копирующий конструктор, то последний будет сгенерирован компилятором вместо вас. Это правило работало в С++98 и остается справедливым в C++11.

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

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

Этот вывод справедлив и в обратном направлении. Объявление в классе перемещающей операции (конструктора или присваивания) приводит к тому, что компиляторы не генерируют копирующие операции. (Копирующие операции отключаются с помощью их удаления; см. раздел 3.5). В конце концов, если почленное перемещение не является корректным способом перемещения, то нет причин ожидать, что почленное копирование окажется корректным способом копирования. Это выглядит как возможное нарушение работоспособности кода С++98, поскольку условия, при которых разрешена генерация операций копирования, являются более ограничивающими в C++11, чем в С++98, но на самом деле это не так. Код С++98 не может иметь перемещающие операции, поскольку в С++98 нет такого понятия, как “перемещение” объектов. Единственный способ для старого класса иметь пользовательские перемещающие операции — это если они будут добавлены в коде С++11. Но классы, которые изменены таким образом, чтобы использовать преимущества семантики перемещений, обязаны играть по правилам С++11, касающимся генерации специальных функций-членов.


Еще от автора Скотт Мейерс
Эффективное использование 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 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.