Хабрахабр

[Перевод] Современный C++ != (Самый)Новый Стандарт

Здесь «новый» может означать что угодно от C++11 до C++17, или даже то, что уже сейчас доступно из C++20. Термин «современный C++» часто используется как синоним выражения «код, использующий новый стандарт C++». Я думаю, что современный C++ — это нечто большее, не ограничивающееся добавлением флага -std=c++17.

Что значит «современный»?

Если поискать значение слова «современный» в сети, одним из первых мы найдем определение из словаря Merriam-Webster. Вот две части, относящиеся к C++:

[...]

2: involving recent techniques, methods, or ideas: (up-to-date) modern methods of communication

3 capitalized: of, relating to, or having the characteristics of the present or most recent period of development of a language — Modern English

[...]

Часто эти новые возможности поддерживают или включают новые техники, но многие из них существовали уже достаточно долгое время. Техники, методы и идеи имеют отношение к чему-то большему, чем просто новые возможности языка. Это относится к тому, как мы комбинируем старые и новые возможности, и это нечто большее, чем просто рабочая программа на C++, или то, что включено в стандартную библиотеку. Что касается характеристик развития языка, в их основе лежит то, как мы используем язык.

Однако, нужно помнить, что самые активные люди в сообществе, которые говорят или пишут о «современном C++», это чаще всего первопроходцы. Можно поспорить, что возможности, существовавшие со времен C++98, не входят в современный C++, потому что они существуют слишком давно. Большинство использует, изучает и даже преподает старый добрый «C с классами» из 90-х, что делает многие методы, которые там не используются, частью современного C++.

Помимо новых возможностей

Что же из доступного в C++98 я считаю принадлежащим к категории «современный C++»? Вот неполный список некоторых важных возможностей и идей:

RAII

RAII расшифровывается как «получение ресурса есть инициализация», или «получение ответственности есть инициализация». Хотя название делает упор на «инициализацию», ключевая часть здесь, на самом деле — это деструктор. Детерминированное освобождение ресурсов — одна из основных характеристик C++, которая отличает его от большинства других языков. Для многих — это самая важная характеристика.

Если вам нужен надежный способ сделать некоторое действие, а потом отменить его на выходе из некоторой области видимости или при уничтожении объекта, RAII — то, что вам нужно. RAII может использоваться для надежного управления многими вещами, такими как память (например, std::vector, std::string), дескрипторы файлов (std::fstream), сетевые соединения, мьютексы, соединения с базами данных, а также сущности, которые имеют отдаленное отношение к ресурсам.

В случае исключений такая очистка не происходит, так что в этой ситуации RAII — то, что вам нужно. Я видел много кода, в котором ручная чистка при завершении функций превращалась в кошмар. Даже если вы не используете исключения, досрочный выход из функций может существенно улучшить ваш код, но только если вам не нужно проводить чистку.

Определенно, техника RAII входит в современный C++, хотя она и была доступна с самого начала.

Строгая типизация

Идея строгой типизации очень популярна в последнее время. В прошлом любые идентификаторы, размеры, почтовые индексы, цены и так далее представлялись через int или double, или другой арифметический тип. То, что они были совместимы, совершенно несвязанные друг с другом значения, которые по чистой случайности имеют один тип, было источником багов, но что поделать? По крайней мере, компилятор молча не преобразует числа и массивы в строки!

Просто создайте разные типы для идентификаторов, почтовых индексов, размеров (нет, без typedef, спасибо) и так далее. На деле получается, что система типов C++ и абстракции с нулевой стоимостью*, которые предоставляет нам компилятор, позволяют сделать многое. Если вам интересно, посмотрите один из докладов Björn Fahller, Jonathan Boccara или Jonathan Müller.

*(Даже если стоимость абстракции ненулевая, докажите, что она неприемлема прежде чем отказываться от нее)

Но если взглянуть на код, выходит, что люди часто предпочитают писать циклы вручную. Если не считать некоторых недавних дополнений, <algorithm> был в стандартной библиотеке с самого начала. Причины разнятся от незнания того, какие стандартные алгоритмы доступны, до веры в то, что «шаблоны слишком медленные» (часто без объяснения, по сравнению с чем).

Программирование этапа компиляции

Вещи вроде метапрограммирования с использованием шаблонов применялись со времен C++98. Логика, выполняемая на этапе компиляции, может существенно уменьшить сложность на этапе выполнения. В прошлом ее было неудобно использовать. Синтаксис шаблонов отличается в сторону усложнения от возможностей, которые есть в последних стандартах. Это что-то вроде отдельного языка, который нам приходится учить. Однако, такие вещи как диспетчеризация тегов или типажи не слишком сложны для использования и написания.

Я считаю использование логики этапа компиляции частью современного C++, потому что оно отделяет C++ от вездесущего «C с классами». Да, большинство типажей в стандартной библиотеке появилось с приходом C++11, но писать их под свои нужды не слишком сложно, и некоторые наиболее общие из них были в Boost до C++11.

Заключение

Современный C++ имеет отношение не к новым стандартам, а к тому, как мы пишем наши программы. Во-первых, на C++98 можно писать в более или менее современном стиле. Во-вторых, «C с классами и range-based for циклами» — это еще не современный C++. Новые возможности языка и библиотек помогают нам писать в стиле современного C++, но не они делают наш код современным C++.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть