Зачем что-то обещать или почему noexcept меняет поведение кода? | OTUS
⚡ Подписка на курсы OTUS!
Интенсивная прокачка навыков для IT-специалистов!
Подробнее

Курсы

Программирование
Разработчик чат-ботов и приложений для виртуальных ассистентов
-15%
PHP Developer. Professional Алгоритмы и структуры данных Scala-разработчик PHP Developer. Basic C# Developer. Professional
-23%
C# ASP.NET Core разработчик Python Developer. Basic Python Developer. Professional Cloud Solution Architecture Специализация iOS
-25%
HTML/CSS Android Developer. Professional React.js Developer Unity Game Developer. Professional NoSQL Java Developer. Professional Highload Architect C++ Developer. Basic Web-разработчик на Python Unity Game Developer. Basic Интенсив «Оптимизация в Java» Супер-практикум по использованию и настройке GIT Symfony Framework Java Developer. Basic Супер-интенсив "Tarantool"
Инфраструктура
MongoDB
-30%
Разработчик чат-ботов и приложений для виртуальных ассистентов
-15%
Administrator Linux. Professional
-26%
Network engineer Administrator Linux. Advanced Специализация Administrator Linux
-25%
Разработчик программных роботов (RPA) на базе UiPath и PIX
-27%
NoSQL Инфраструктурная платформа на основе Kubernetes Highload Architect Мониторинг и логирование: Zabbix, Prometheus, ELK Супер-практикум по использованию и настройке GIT Administrator Linux.Basic Экспресс-курс «IaC Ansible» Экспресс-курс по управлению миграциями (DBVC) Экспресс-курс "Версионирование и командная работа с помощью Git" Network engineer. Basic Основы Windows Server
Корпоративные курсы
Безопасность веб-приложений MongoDB
-30%
Разработчик чат-ботов и приложений для виртуальных ассистентов
-15%
Agile Project Manager Руководитель поддержки пользователей в IT
-10%
Промышленный ML на больших данных Cloud Solution Architecture Внедрение и работа в DevSecOps Spark Developer Reverse-Engineering IT-Recruiter Machine Learning. Professional Интенсив «Оптимизация в Java» Супер-практикум по использованию и настройке GIT Экcпресс-курс «ELK» Enterprise Architect Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes» Экспресс-курс «Введение в непрерывную поставку на базе Docker» Вебинар CERTIPORT
Специализации Курсы в разработке Подготовительные курсы Подписка
+7 499 938-92-02

Зачем что-то обещать или почему noexcept меняет поведение кода?

С++Deep_14.06_SITE.png

Если бы по телевизору показывали рекламу языка C++, наверняка, в ней бы было что-то вроде:

«С добавлением move-семантики вы получаете бесплатное увеличение производительности за счёт избавления от нецелесообразных операций копирования. Просто перекомпилируйте свой проект новой версией компилятора с поддержкой 11 или 14 стандарта и радуйтесь ускорению работы программы!».

Стоит ли верить такой рекламе?

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

  1. В классе не объявлены никакие пользовательские копирующие операции (никаких конструкторов копирования и никаких операторов присваивания);
  2. В классе не объявлены никакие пользовательские операции перемещения (никаких конструкторов перемещения и никаких операторов перемещения);
  3. В классе не объявлен пользовательский деструктор.

Допустим, мы не сможем удовлетворить какое-нибудь из этих требований, и нам придётся реализовать, скажем, пользовательские операции копирования. Очевидно, тогда придётся определить и пользовательские операции перемещения.

Получим ли мы автоматическое ускорение старого кода, как обещано в рекламе?

Предположим, мы взяли старый код и добавили к уже существующему (и используемому) классу операции копирования и перемещения. В итоге получилось что-то вроде следующего:

struct SomeClass {

    SomeClass();
    ~SomeClass();

    SomeClass(const SomeClass&);
    SomeClass(SomeClass&&);

    SomeClass& operator=(const SomeClass&);
    SomeClass& operator=(SomeClass&&);

};

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

К чему это приведёт?

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

Рассчитывать на перемещение мы сможем только в тех случаях, когда в коде присутствует явная работа с r-value. Например, вот так: SomeClass a; SomeClass b(std::move(a));

А разве есть другие?

Да, есть и другие. И эти другие зачастую являются более желанными, чем явные случаи использовать перемещения. Примерами таких неявных случаев использования перемещения являются: алгоритмы, внутренние реалокации памяти с дальнейшим перемещением объектов. Если перемещающие операторы не помечены спецификатором noexcept, компилятор предпочтёт не рисковать и выберет копирующие операции.

Вывод

Использование спецификатора noexcept (или наоборот его неиспользование) может серьёзно изменить производительность вашей программы.

Есть вопросы? Напишите в комментариях!

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

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

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

Автор
0 комментариев
Для комментирования необходимо авторизоваться
🔥 Выгодные предложения
Подборка курсов, которые можно приобрести по выгодной цене только до конца июля!