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

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

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

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

Это означает, что "копирующая" версия ma keWidget на самом деле копи­рования не выполняет.Перемещающая версия ma keW idget делает только то, о чем говорит ее имя (в предпо­ложении наличия перемещающего конструктора Widget ) : она перемещает содержимое w2Такими локапьными объектами я1111яются бопьшинство покапьных переменных (например, такиекак w в ma keWidget ) , а также временные объекты, создаваемые как часть инструкции ret urn.Параметры функции на такое звание претендовать нс могут.

Некоторые программисты разпичаютприменение RVO к именованным и неимепованным (т.е. временным) локальным объектам, огра­ничивая термин "RVO" неименованными объектами и назы11ая его применение к именованнымобъектам оптимизацией именованных возвращаемых значений (named return value optimization-NRVO).5.3. Используйте std::move дл я rvalue-cc ыл o к, а std::forward - дл я универсальных ссылок181в местоположение возвращаемого значения makeWidget .

Но почему компиляторы не ис­пользуют RVO для устранения перемещения, вновь создавая w в памяти, выделеннойдля возвращаемого значения функции? Ответ прост: они не могут. Условие (2) предусма­тривает, что RVO может быть выполнена, только если возвращается локальный объект,но в перемещающей версии ma keW i d g e t это не так. Посмотрим еще раз на инструкциюreturn:return std: : move (w) ;То, что здесь возвращается, не является локальным объектом w; это ссьтка на wре­зультат s t d : : move ( w ) . Возврат ссылки на локальный объект не удовлетворяет услови­ям, требующимся для применения RVO, так что компиляторы вынуждены перемещать wв местоположение возвращаемого значения функции.

Разработчики, пытаясь с помощьюприменения s t d : : move к возвращаемой локальной переменной помочь компиляторамоптимизировать код, на самом деле ограничивают возможности оптимизации, доступ­ные их компиляторам!Но RVOэто всего лишь оптимизация. Компиляторы не обязаны устранять опе­рации копирования и перемещения даже тогда, когда это им позволено. Возможно, выпараноик и беспокоитесь о том, что ваши компиляторы будут выполнять операции ко­пирования, просто потому, что они могут это делать.

А может, вы настолько глубоко раз­бираетесь в ситуации, что в состоянии распознать случаи, когда компиляторам трудноприменять RVO, например когда различные пути выполнения в функции возвращаютразные локальные переменные. (Компиляторы должны генерировать код для построениясоответствующей локальной переменной в памяти, выделенной для возвращаемого зна­чения функции, но как компиляторы смогут определить, какая локальная переменнаядолжна использоватьсяn В таком случае вы можете быть готовы заплатить цену переме­щения как гарантию того, что копирование выполнено не будет. Иначе говоря, вы може­те продолжать думать, что применение s t d : : move к возвращаемому локальному объектуразумно просто потому, что при этом вы спокойны, зная, что вам не придется платить закопирование.В этом случае применение std : : move к локальному объекту все равно остается пло­хой идеей. Часть стандарта, разрешающая применение RVO, гласит далее, что если ус­ловия для применения RVO выполнены, но компиляторы предпочитают не выполнятьудаление копирования, то возвращаемый объект должен рассматриваться как rvalue.

Посути, стандарт требует, чтобы, когда оптимизация RVO разрешена, к возвращаемому ло­кальному объекту либо применялось удаление копирования, либо неявно применяласьфункция s t d : : move. Так что в "копирующей" версии makeWidget--Widget makeWidget ( )1 1 Какиранее{Widget w ;return w;182Гnава 5. Rvalue-ccыnки, семантика перемещений и п рямая передачакомпиляторы должны либо устранить копирование w, либо рассматривать функцию, какесли бы она была написана следующим образом:Widget makeWidget ( )(Widget w;return std: : move(w) ; / / Рассматривает w как rvalue , поскольку/ / удаление копирования не выполняетсяСитуация аналогична для параметров функции, передаваемых по значению.

Они неимеют права на удаление копирования при их возврате из функции, но компиляторыдолжны рассматривать их в случае возврата как rvalue. В результате, если ваш исходныйтекст выглядит какWidget makeWidget (Wiclget w ) / / Передаваемый по значению параметр// имеет тот же тип, что и1 1 возвращаемый тип функции{return w;компиляторы должны рассматривать его, как если бы он был написан какWidget makeWidget (Widget w ){return std: : move (w) ;11 w рассматривается как rvalueЭто означает, что, используя s t d : : move для локального объекта, возвращаемого функ­цией по значению, вы не можете помочь компилятору (он обязан рассматривать локальныйобъект как rvaJue, если не выполняет удаления копирования), но вы, определенно, в со­стоянии ему помешать (препятствуя RVO).

Есть ситуации, когда применение s t d : : moveк локальной переменной может быть разумным (т.е. когда вы передаете ее функции и зна­ете, что больше вы ее использовать не будете), но эти ситуации не включают применениеs t d : : rnove в качестве части инструкции return, которая в противном случае претендовалабы на оптимизацию RVO, или возврат параметра, передаваемого по значению.Сnедует запомнить•Применяйте s t d : : move к rvаluе-ссылкам, а s t d : : forwardкам, когда вы используете их в последний раз.•Делайте то же для rvalue- и универсальных ссылок, возвращаемых из функцийпо значению.•Никогда не применяйте s t d : : move и s t d : : forward к локальным объектам, которыемогут быть объектом оптимизации возвращаемого значения.5.3 . Испол ьзуйте std::move АЛА rvalue-ccы л oк, а std::forward--к универсальным ссыл­АЛА универсальных ссы л ок1 83S .4.

И збе rайте пере r рузок дnя универсаnьных ссыnокПредположим, что вам надо написать функцию, которая принимает в качестве па­раметра имя, записывает в журнал текущие дату и время, а затем добавляет имя в гло­бальную структуру данных. Вы могли бы начать с функции, которая имеет примерноследующий вид:std: : multiset<std : : s triпg> пames ; / / Глобальная структура данныхvoid logAndAdd ( const std: : s tring& пате ){auto поw11 Получение текущего времениstd: : chroпo : : system_clock : : поw ( ) ;/ / Создание журнальной записиlog ( пow, " logAndAdd " ) ;пames .

emplace (пame ) ;11 Добавление паmе в глобальную1 1 структуру даннь� ; emplace1 1 см. в разделе 8 . 2=Этот код не является неразумным, но он не такой эффективный, каким мог бы быть. Рас­смотрим три потенциальных вызова:std: : st ring petName ( "Darla" ) ;11 lvalue типа std : : striпglogAndAdd (petName) ;logAndAdd ( std: : strinq ( "Persephone") ) ; // rvalue типа std : : striпglogAndAdd ( "Patty Doq" ) ;/ / Строковый литералВ первом вызове параметр паmе функции 1 ogAпdAdd связывается с перемен­ной petName. Внутри logAпdAdd параметр паmе в конечном итоге передается в вызовпames . emplace.

Поскольку паmе является lvalue, он копируется в пames. Избежать этогокопирования невозможно, так как lvalue (petName) передается в функцию logAпdAdd.Во втором вызове параметр name связывается с гvalue (временный объектstd : : st r i пg, явно созданный из строки " Persephoпe " ) . Параметр паmе сам по себе яв­ляется lvalue, так что он копируется в пames, но мы отдаем себе отчет, что, в принципе,это значение может быть перемещено в пames. В этом вызове мы платим за копирование,но мы должны быть способны сделать то же с помощью перемещения.В третьем вызове параметр паmе опять связывается с rvalue, но в этот раз со времен­ным объектом s t d : : s t r iпg, который неявно создается из " Patty Dog'' . Как и во вто­ром вызове, паmе копируется в names, но в этот раз аргумент, изначально переданныйв logAпdAdd, был строковым литералом.

Если бы строковый литерал непосредственнопередавался в emplace, в создании временного объекта std : : str i пg не было бы необ­ходимости вообще. Вместо этого функция emplace использовала бы строковый литералдля создания объекта std : : str ing непосредственно в std : : mu l t i set. Таким образом,в этом третьем вызове мы платим за копирование std : : st ri ng, при том что нет причинплатить даже за перемещение, не говоря уже о копировании.Неэффективность второго и третьего вызовов logAndAdd можно устранить, перепи­сав эту функцию так, чтобы она принимала универсальную ссылку (см. раздел 5.2) и,1 84Глава S . Rvа l uе-ссылки , семантика перемещений и прямая передачасогласно разделу 5.3, передавала ее с помощью s t d : : f o rward функции ernp l a ce .

Резуль­тат говорит сам за себя:tamplate<t:ypen.ame Т>void logAndAdd (T&& name ){auto now = std : : chrono : : system_clock : : now ( ) ;log ( now, " logAndAdd " ) ;names . emplace ( std : : forward<Т> (name ) ) ;std : : string petName ( " Darla " ) ;11 Как и ранееlogAndAdd (petNaшe) ;11 Как и ранее , копирова­// ние lvalue в multisetlogAndAdd (std: : strinq ( "Persephone") ) ; / / Перемещение rvalue11 вместо копированияlogAndAdd ( "Patty Dog" ) ;11 Соэдание s td : : string1 1 в mult i set вместо/ /копирования временного11 s t d : : st ringУра, получена оптимальная эффективность!Если бы это был конец истории, мы могли бы остановиться и гордо удалиться, ноя не сказал вам, что клиенты не всегда имеют непосредственный доступ к именам, тре­бующимся logAndAdd.

Некоторые клиенты имеют только индекс, который l ogAndAdd ис­пользует для поиска соответствующего имени в таблице. Для поддержки таких клиентоввыполняется перегрузка функции logAndAdd:std : : string nameFromidx ( int idx ) ; / / Возвращает имя,1 1 соответствующее idx/ / Новая перегрузкаvoid logAndAdd ( int iclx){auto nows t d : : chrono : : system_clock : : now ( ) ;log ( now, " logAndAdd " ) ;name s . emplace (nameFroшiclx (iclx) ) ;=Разрешение перегрузки работает, как и следовало ожидать:std: : s tring petName ( " Darla" ) ;1 1 Как и ранее11 Как и ранее, эти вызовыlogAndAdd (petName ) ;logAndAdd ( s td : : string ( " Persephone " ) ) ; 11 приводят к испольэова­// нию перегрузки для Т&&logAndAdd ( " Patty Dog" ) ;logAndAdd ( 2 2 ) ;1 1 Вызов int -перегруэкиS.4. Избегайте перегрузок дnя ун мверсаnьных ссыпок1 85На самом деле разрешение работает, как ожидается, только если вы не ожидаете слиш ком многого.

Предположим, клиент имеет переменную типа short , хранящую индекс,и передает ее функции logAndAdd:short name idx ;11 Дает значение переменной name idxlogAndAdd ( namei dx ) ; // Ошибка 1Комментарий в последней строке, может быть, не слишком понятен, так что позвольтемне пояснить, что же здесь произошло.Имеется две перегрузки logAndAdd.

Одна из них, принимающая универсальную ссыл­ку, может вывести тип Т как short, тем самым приводя к точному соответствию. Пере­грузка с параметром int может соответствовать аргументу short только с повышением.Согласно обычным правилам разрешения перегрузки точное соответствие побеждаетсоответствие с повышением, так что вызывается перегрузка для универсальной ссылки.В этой перегрузке параметр name связывается с переданным значением типа short.Таким образом, name передается с помощью s t d : : forward функции-члену emplace объ­екта name s ( s t d : : mu l t i s e t < s t d : : s t r i n g > ) , которая, в свою очередь, послушно пере­дает его конструктору s t d : : s t ri ng.

Но конструктора s t d : : s t r i ng, который принималбы значение short, не существует, так что вызов конструктора s t d : : s t r i ng в вызовеmul t i se t : : emplace в вызове logAndAdd неудачен. Все дело в том, что перегрузка для уни­версальной ссылки точнее соответствует аргументу типа short, чем перегрузка для int.Функции, принимающие универсальные ссылки, оказываются самыми жадными в С++.Они в состоянии выполнить инстанцирование с точным соответствием практическидля любого типа аргумента (несколько видов аргументов, для которых это не так, описа­ны в разделе 5.8).

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

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

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

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