Термин «современный C++» часто используется как синоним выражения «код, использующий новый стандарт C++». Здесь «новый» может означать что угодно от C++11 до C++17, или даже то, что уже сейчас доступно из C++20. Я думаю, что современный 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++98, не входят в современный C++, потому что они существуют слишком давно. Однако, нужно помнить, что самые активные люди в сообществе, которые говорят или пишут о «современном C++», это чаще всего первопроходцы. Большинство использует, изучает и даже преподает старый добрый «C с классами» из 90-х, что делает многие методы, которые там не используются, частью современного C++.
Помимо новых возможностей
Что же из доступного в C++98 я считаю принадлежащим к категории «современный C++»? Вот неполный список некоторых важных возможностей и идей:
RAII
RAII расшифровывается как «получение ресурса есть инициализация», или «получение ответственности есть инициализация». Хотя название делает упор на «инициализацию», ключевая часть здесь, на самом деле — это деструктор. Детерминированное освобождение ресурсов — одна из основных характеристик C++, которая отличает его от большинства других языков. Для многих — это самая важная характеристика.
RAII может использоваться для надежного управления многими вещами, такими как память (например, std::vector, std::string), дескрипторы файлов (std::fstream), сетевые соединения, мьютексы, соединения с базами данных, а также сущности, которые имеют отдаленное отношение к ресурсам. Если вам нужен надежный способ сделать некоторое действие, а потом отменить его на выходе из некоторой области видимости или при уничтожении объекта, RAII — то, что вам нужно.
Я видел много кода, в котором ручная чистка при завершении функций превращалась в кошмар. В случае исключений такая очистка не происходит, так что в этой ситуации RAII — то, что вам нужно. Даже если вы не используете исключения, досрочный выход из функций может существенно улучшить ваш код, но только если вам не нужно проводить чистку.
Определенно, техника RAII входит в современный C++, хотя она и была доступна с самого начала.
Строгая типизация
Идея строгой типизации очень популярна в последнее время. В прошлом любые идентификаторы, размеры, почтовые индексы, цены и так далее представлялись через int или double, или другой арифметический тип. То, что они были совместимы, совершенно несвязанные друг с другом значения, которые по чистой случайности имеют один тип, было источником багов, но что поделать? По крайней мере, компилятор молча не преобразует числа и массивы в строки!
На деле получается, что система типов C++ и абстракции с нулевой стоимостью*, которые предоставляет нам компилятор, позволяют сделать многое. Просто создайте разные типы для идентификаторов, почтовых индексов, размеров (нет, без typedef, спасибо) и так далее. Если вам интересно, посмотрите один из докладов Björn Fahller, Jonathan Boccara или Jonathan Müller.
*(Даже если стоимость абстракции ненулевая, докажите, что она неприемлема прежде чем отказываться от нее)
Если не считать некоторых недавних дополнений, <algorithm> был в стандартной библиотеке с самого начала. Но если взглянуть на код, выходит, что люди часто предпочитают писать циклы вручную. Причины разнятся от незнания того, какие стандартные алгоритмы доступны, до веры в то, что «шаблоны слишком медленные» (часто без объяснения, по сравнению с чем).
Программирование этапа компиляции
Вещи вроде метапрограммирования с использованием шаблонов применялись со времен C++98. Логика, выполняемая на этапе компиляции, может существенно уменьшить сложность на этапе выполнения. В прошлом ее было неудобно использовать. Синтаксис шаблонов отличается в сторону усложнения от возможностей, которые есть в последних стандартах. Это что-то вроде отдельного языка, который нам приходится учить. Однако, такие вещи как диспетчеризация тегов или типажи не слишком сложны для использования и написания.
Да, большинство типажей в стандартной библиотеке появилось с приходом C++11, но писать их под свои нужды не слишком сложно, и некоторые наиболее общие из них были в Boost до C++11. Я считаю использование логики этапа компиляции частью современного C++, потому что оно отделяет C++ от вездесущего «C с классами».
Заключение
Современный C++ имеет отношение не к новым стандартам, а к тому, как мы пишем наши программы. Во-первых, на C++98 можно писать в более или менее современном стиле. Во-вторых, «C с классами и range-based for циклами» — это еще не современный C++. Новые возможности языка и библиотек помогают нам писать в стиле современного C++, но не они делают наш код современным C++.
Автор: Andrey2008