Copy/move elision и универсальные ссылки | OTUS
⚡Подписка от OTUS!
Собери свой пул курсов на выгодных условиях. Подробности в чате →
Написать в чат

Курсы

Программирование
Unity Game Developer. Basic
-15%
Разработчик программных роботов (RPA) на базе UiPath и PIX
-6%
Разработчик C#
-8%
Алгоритмы и структуры данных
-8%
Backend-разработчик на PHP
-8%
JavaScript Developer. Professional
-9%
iOS Developer. Professional
-8%
Базы данных
-12%
C# ASP.NET Core разработчик
-6%
Python Developer. Basic
-10%
Java Developer. Professional Web-разработчик на Python Android Developer. Basic PostgreSQL Software Architect Reverse-Engineering. Professional Kotlin Backend Developer React.js Developer VOIP инженер Нереляционные базы данных Scala-разработчик Супер-практикум по использованию и настройке GIT IoT-разработчик JavaScript Developer. Basic Advanced Fullstack JavaScript developer Unity Game Developer. Professional Супер-интенсив Azure
Инфраструктура
Супер-интенсив "Версионирование и командная работа с помощью Git"
-30%
Administrator Linux. Professional
-5%
Супер-интенсив «CI/CD или Непрерывная поставка с Docker и Kubernetes»
-30%
Разработчик программных роботов (RPA) на базе UiPath и PIX
-6%
Administrator Linux. Advanced
-8%
Infrastructure as a code in Ansible
-12%
Network engineer
-4%
MS SQL Server Developer
-8%
Cloud Solution Architecture Highload Architect Разработчик голосовых ассистентов и чат-ботов Мониторинг и логирование: Zabbix, Prometheus, ELK Супер-практикум по работе с протоколом BGP Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes Архитектор сетей Супер-интенсив «IaC Ansible»
Специализации Курсы в разработке Подготовительные курсы
+7 499 938-92-02

Copy/move elision и универсальные ссылки

Copy/move elision представляет собой оптимизацию, когда компилятор может убрать определенные вызовы конструктора копирования и деструктора, но только при возврате объекта из функции и если тип возвращаемого объекта совпадает с типом функции.

В результате при возврате из функции применение std::move() способно понизить производительность, ограничив тем самым компилятор в Copy elision оптимизации, ведь отсутствие конструктора, по сути, быстрее, чем конструктор перемещения.

Screenshot_1-1801-593795.png

В данном случае std::move() лишь замедляет код, добавляя излишний вызов String(String&& other) и ~String(). При этом стоит учесть, что в C++20 copy/move elision может быть расширен, в результате чего в ряде случаев применение std::move() тоже снизит производительность.

Универсальные ссылки

Вернувшись к теме одной из предыдущих статей, скажем, что универсальные ссылки способны быть как rvalue-, так и lvalue-ссылкой — это зависит от аргументов либо результата функции. Применяются они в шаблонах и в auto&&:

Screenshot_2-1801-5db497.png

На основе данного шаблона компилятор генерирует две функции, причем одна из них принимает lvalue, а вторая — rvalue, если они будут применяться. Когда разработчик желает использовать перемещение для rvalue-ссылки и обычное простое копирование для lvalue-ссылки, он может применить std::forward(), приводящий свой аргумент к rvalue лишь тогда, когда его тип — это rvalue-ссылка. Что касается std::forward(), то он требует явного указания шаблонного параметра.

Собственно говоря, универсальная ссылка просто обязана быть шаблонным параметром, откуда в нашем примере и взялось странное определение шаблона функции в формате T&&. Таким образом, std::vector<T>&& — это уже не универсальная ссылка, а rvalue-ссылка.

Но вообще, особой разницы между универсальной и rvalue-ссылкой не существует. Можно сказать, что универсальная ссылка является лишь удобной абстракцией над rvalue-ссылкой, которой, как раз таки, многие и пользуются. Но как же тогда rvalue-ссылка превращается в lvalue-ссылку, имея lvalue-аргумент? Ответ — путем свертывания ссылок.

Когда происходит вызов template_func(string), компилятор генерирует следующий заголовок функции:

Screenshot_3-1801-81838a.png

Таким образом, получается ссылка на ссылку! Сделать так вручную невозможно, однако шаблоны могут. Потом компилятор свертывает ссылку на ссылку, а происходит это по определенному правилу: результатом свертывания становится rvalue-ссылка, но лишь в том случае, если обе ссылки — это rvalue-ссылки. И, как раз из-за данного безобразия и проще применять абстракцию универсальных ссылок.

Источник

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться