Главная » Просмотр файлов » С. Мейерс - Эффективный и современный C++

С. Мейерс - Эффективный и современный C++ (1114942), страница 45

Файл №1114942 С. Мейерс - Эффективный и современный C++ (С. Мейерс - Эффективный и современный C++) 45 страницаС. Мейерс - Эффективный и современный C++ (1114942) страница 452019-05-08СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 45)

Именно поэтому сочетание перегрузки и универсальной ссылки почтивсегда является плохой идеей: перегрузка для универсальных ссылок годится для гораздобольшего количества типов аргументов, чем обычно ожидает разработчик перегрузок.Простой способ свалиться в эту яму - написать конструктор с прямой передачей.Небольшое изменение функции l ogAndAdd демонстрирует эту проблему. Вместо напи­сания свободной функции, которая принимает либо s t d : : s t ri ng, либо индекс, которыйможно использовать для поиска s t d : : s t ring, представим себе класс Person с конструк­торами, которые выполняют те же действия:class Person {puЫ i c :template<typename Т>// Конструктор с прямой передачейexpl icit Person ( T & & n): name ( s td : : forward<T> ( n ) ) { } / / инициализирует члены-данныеexplicit Person ( int idx )/ / Конструктор с параметром int: name ( nameFromidx ( idx ) ) { }private :std: : string name ;};1 86Гnава 5.

Rvalue-cc ыnки, семантика перемещений и прямая передачаКак и в случае с logAndAdd, передача целочисленного типа, отличного от int (напри­мер, std : : s i ze_t, short, l ong и т.п.), будет вызывать перегрузку конструктора для уни­версальной ссылки вместо перегрузки для i nt, и это будет вести к ошибкам компиля­ции. Однако проблема гораздо хуже, поскольку в Person имеется больше перегрузок,чем видит глаз.

В разделе 3 . 1 1 поясняется, что при соответствующих условиях С++ будетгенерировать как копирующие, так и перемещающие конструкторы, и это так и будет,даже если класс содержит шаблонный конструктор, который при инстанцировании в со­стоянии дать сигнатуру копирующего или перемещающего конструктора. Если такимобразом генерируются копирующий и перемещающий конструкторы для Person, классPerson будет выглядеть, по сути, следующим образом:class Person [puЬlic :/ / Конструктор с прямой передачейtemplate<typename Т>explicit Person (T&& n ): name ( std : : forward<T> ( n ) ) [ )explicit Person ( int idx) ;/ / Конструктор от intPerson (const Person& rhs ) ; / / Копирующий конструкторPerson (Person&& rhs) ;/! ( сгенерирован компилятором)/ / Перемещающий конструктор// ( сгенерирован компилятором));Это приводит к поведению, интуитивно понятному, только если вы потратили на ра­боту с компиляторами и общение с их разработчиками столько времени, что забыли,каково это - быть человеком:Person р ( "Nапсу" ) ;auto cloneOfP ( p ) ; / / Создание нового объекта Person из р ;1 1 этот код н е компилируется 'Здесь мы пытаемся создать объект Person из другого объекта Person, что представ­ляется очевидным случаем копирующего конструирования (р является lvalue, так чтоможно выбросить из головы все фантазии на тему копирования с помощью операции перемещения).

Но этот код не вызывает копирующий конструктор - он вызыва­ет конструктор с прямой передачей. Затем эта функция будет пытаться инициализиро­вать член-данные s t d : : s t ring объекта Person значением из объекта Person (р}. Классstd : : st ring не имеет конструктора, получающего параметр типа Person, так что вашкомпилятор будет вынужден просто развести руками и наказать вас длинными и непо­нятными сообщениями об ошибках."Но почему, - можете удивиться вы, - вызывается конструктор с прямой переда­чей, а не копирующий конструктор? Мы же инициализируем Person другим объектомPerson!" Да, это так, но компиляторы приносят присягу свято соблюдать правила С++,а правила, имеющие отношение к данной ситуации, - это правила разрешения вызововперегруженных функций.С(S.

4.J)И збегайте перегрузок для универсальных ссылок187Компиляторы рассуждают следующим образом. cloneOf P инициализируется некон­стантным lvalue (р}, а это означает, что шаблонный конструктор может быть инстанци­рован для получения неконстантного lvalue типа Person. После такого инстанцированиякласс Person выглядит следующим образом:class Person {puЬl ic :explicit Person (Person& n)/ / Инстанцирован из: name ( std : : forward<Persoп&> ( n ) ) { } / / шаблона с прямой1 1 передачейexpl icit Person ( int idx ) ;Persoп ( const Person& rhs ) ;)/ / Как и ранее/ / Копирующий конструктор11 ( сгенерирован компилятором);В инструкцииauto cloneOfP ( p ) ;рможет быть передан либо копирующему конструктору, либо инстанцированному ша­блону. Вызов копирующего конструктора для точного соответствия типа параметра тре­бует добавления к р модификатора const; вызов инстанцированного шаблона никакихдобавлений не требует.

Таким образом, перегрузка, сгенерированная из шаблона, пред­ставляет собой лучшее соответствие, так что компиляторы делают то, для чего предна­значены: генерируют вызов той функции, которая соответствует наилучшим образом."Копирование" неконстантных lvalue типа Person, таким образом, осуществляется кон­структором с прямой передачей, а не копирующим конструктором.Если мы немного изменим пример, так, чтобы копируемый объект был константным,то увидим совершенно иную картину:const Person cp ( "Nancy" ) ; / / Теперь объект константныйauto cloneOfP ( ер ) ;// Вызов копирующего конструктора !Поскольку копируемый объект теперь объявлен как const, он в точности соответствуеттипу параметра, получаемого копирующим конструктором.

Шаблонизированный кон­структор также может быть инстанцирован таким образом, чтобы иметь ту же сигнатуру:class PersonpuЫic :explicit Person (const Person& n) ; / / Инстанцирован из шаблонаPerson ( const Person& rhs ) ;/ / Копирующий конструктор1 1 ( сгенерирован компилятором)};Но это не имеет значения, поскольку одно из правил разрешения перегрузок в С++гласит, что в ситуации, когда инстанцирование шаблона и нешаблонная функция (т.е."нормальная" функция) имеют одинаково хорошее соответствие, предпочтение отдается1 88Глава S. Rvаluе-ссылки, семантика перемещений и прямая передачанормальной функции.

Поэтому все козыри оказываются на руках копирующего кон­структора (нормальной функции) с той же самой сигнатурой.(Если вам интересно, почему компиляторы создают копирующий конструктор, еслиони могут инстанцировать шаблонный конструктор с той же сигнатурой, обратитеськ разделу 3. 1 1 .)Взаимодействие между конструкторами с прямой передачей и сгенерированнымикомпилятором операциями копирования и перемещения становится еще более сложным,когда в картину включается наследование.

В частности, обычные реализации копирую­щих и перемещающих операций производного класса ведут себя совершенно неожидан­но. Взгляните на следующий код:class Spec i alPerson : puЫic PersonpuЫ ic:SpecialPerson ( const Specia lPerson& rhs ) / / КопирующийPerson (rhs)11 конструктор ; вызывает конструктор11 базового класса с прямой передачей !{ ". )SpecialPerson ( SpecialPerson&& rhs )// ПеремещающийPerson (std: : move (rhs) ) / / конструктор ; вызывает конструктор/ / базового класса с прямой передачей 1{ . )");Как указывают комментарии, копирующий и перемещающий конструкторы произво­дного класса не вызывают копирующий и перемещающий конструкторы базового клас­са; они вызывают конструктор базового класса с прямой передачей! Чтобы понять, по­чему, обратите внимание, что функции производного класса используют аргументы типаSpec i a l Person для передачи в базовый класс, после чего в игру вступает разрешение пере­грузок для конструкторов в классе Person.

В конечном итоге код не будет компилировать­ся, потому что у std : : st ring нет никакого конструктора, принимающего Special Persoп.Я надеюсь, что теперь я убедил вас, что перегрузка для параметров, являющихся универ­сальными ссылками, - это то, чего лучше избегать, насколько это возможно. Но если пере­грузка для универсальной ссылки - плохая идея, то что же делать, если вам нужна функция,которая выполняет передачу большинства типов аргументов, но при этом должна обраба­тывать некоторые из них особым образом? Это яйцо может быть разбито массой способов.Этих способов так много, что я посвятил им целый раздел - раздел 5.5, который идет сразупосле того, который вы сейчас читаете.

Не останавливайтесь, и вы попадете прямо в него.Спедует запомнить•Перегрузка для универсальных ссылок почти всегда приводит к тому, что даннаяперегрузка вызывается чаще, чем вы ожидаете.•Особенно проблематичны конструкторы с прямой передачей, поскольку они обычносоответствуют неконстантным lvalue лучше, чем копирующие конструкторы, и моrутперехватывать вызовы из производного класса копирующих и перемещающих кон­структоров базового класса.S.4. Избегайте перегрузок дnя универсальных ссыпок1 89S .S . Знакомство с а nыернативами пере r рузкидnя универсаnьных ссыпокВ разделе 5.4 поясняется, что перегрузка для универсальных ссылок может приве­сти к целому ряду проблем как для автономных функций, так и для функций-членов (вособенности для конструкторов).

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

Характеристики

Тип файла
PDF-файл
Размер
12,67 Mb
Тип материала
Высшее учебное заведение

Список файлов книги

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6418
Авторов
на СтудИзбе
307
Средний доход
с одного платного файла
Обучение Подробнее