Эффективный и современный С++. 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 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


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

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


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

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


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


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.