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

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

>void processVals(const Ts&... params) // в исходном

>{                                     // тексте С++

> …                                    // Это троеточие озна-

>                                      // чает какой-то код

>}

Объявление >processVals показывает, что я использую ключевое слово >typename при объявлении параметров типов в шаблонах, но это просто мое личное предпочтение; вместо него можно использовать ключевое слово >class. В тех случаях, когда я показываю код, взятый из стандарта С++, я объявляю параметры типа с использованием ключевого слова >class, поскольку так делает стандарт.

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

>void someFunc(Widget w);  // Параметр w функции someFunc

>                          // передается по значению


>Widget wid;               // wid - объект класса Widget


>someFunc(wid);            // В этом вызове someFunc w

>                          // является копией wid, созданной

>                          // копирующим конструктором


>someFunc(std::move(wid)); // В этом вызове SomeFunc w

>                          // является копией wid, созданной

>                          // перемещающим конструктором

Копии rvalue в общем случае конструируются перемещением, в то время как копии lvalue обычно конструируются копированием. Следствием является то, что если вы знаете только то, что объект является копией другого объекта, то невозможно сказать, насколько дорогостоящим является создание копии. В приведенном выше коде, например, нет возможности сказать, насколько дорогостоящим является создание параметра >w, без знания того, какое значение передано функции >someFunc — rvalue или lvalue. (Вы также должны знать стоимости перемещения и копирования >Widget.)

В вызове функции выражения, переданные в источнике вызова, являются аргументами функции. Эти аргументы используются для инициализации параметров функции. В первом вызове >someFunc, показанном выше, аргументом является >wid. Во втором вызове аргументом является >std::move(wid). В обоих вызовах параметром является >w. Разница между аргументами и параметрами важна, поскольку параметры являются lvalue, но аргументы, которыми они инициализируются, могут быть как rvalue, так и lvalue. Это особенно актуально во время прямой передачи, при которой аргумент, переданный функции, передается другой функции так, что при этом сохраняется его “правосторонность” или “левосторонность” (Прямая передача подробно рассматривается в разделе 5.8.)

Хорошо спроектированные функции безопасны с тачки зрения исключений, что означает, что они обеспечивают как минимум базовую гарантию, т.е. гарантируют, что, даже если будет сгенерировано исключение, инварианты программы останутся нетронутыми (т.е. не будут повреждены структуры данных) и не будет никаких утечек ресурсов. Функции, обеспечивающие строгую гарантию, гарантируют, что, даже если будет сгенерировано исключение, состояние программы останется тем же, что и до вызова функции.

Говоря о функциональном объекте, я обычно имею в виду объект типа, поддерживающего функцию-член >operator(). Другими словами, это объект, действующий, как функция. Иногда я использую термин в несколько более общем смысле для обозначения чего угодно, что может быть вызвано с использованием синтаксиса вызова функции, не являющейся членом (т.е. >functionName(arguments)). Это более широкое определение охватывает не только объекты, поддерживающие operator(), но и функции и указатели на функции в стиле С. (Более узкое определение происходит из С++98, более широкое — из C++11.) Дальнейшее обобщение путем добавления указателей на функции-члены дает то, что известно как вызываемый объект (callable object). Вообще говоря, можно игнорировать эти тонкие отличия и просто рассматривать функциональные и вызываемые объекты как сущности в С++, которые могут быть вызваны с помощью некоторой разновидности синтаксиса вызова функции.

Функциональные объекты, создаваемые с помощью лямбда-выражений, известны как замыкания (closures). Различать лямбда-выражения и замыкания, ими создаваемые, приходится редко, так что я зачастую говорю о них обоих как о лямбдах (lambda). Точно так же я редко различаю шаблоны функций (function templates) (т.е. шаблоны, которые генерируют функции) и шаблонные функции (template functions) (т.е. функции, сгенерированные из шаблонов функций). То же самое относится к шаблонам классов и шаблонным классам.

Многие сущности в С++ могут быть как объявлены, так и определены. Объявления вводят имена и типы, не детализируя информацию о них, такую как их местоположение в памяти или реализация:

>extern int x;               // Объявление объекта


>class Widget;               // Объявление класса


>bool func(const Widget& w); // Объявление функции


>enum class Color;           // Объявление перечисления

>                            // с областью видимости


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

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


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

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


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.