Зверь ревет в ответ: возрождение C++

Введение

С момента своего создания в 1979 году как C with Classes C++ превратился в мощный инструмент для миллионов разработчиков программного обеспечения по всему миру. . Согласно опросу, проведенному JetBrains в 2015 году, по всему миру насчитывалось около 4,4 миллиона разработчиков C++. За свою долгую и зачастую бурную историю язык пережил немало взлетов и падений. Он постоянно пытался отразить многочисленные обвинения, выдвигаемые против него, например, в том, что это чрезвычайно сложный и пугающий язык для изучения. В недавней истории другие языки, которые считаются менее сложными и более легкими для изучения, обогнали C++ по популярности в кругах программистов. Одним из таких языков является Java. С момента своего объявления в 1995 году Java покорила сообщество программистов благодаря тому, что она была гораздо более дружелюбна к новичкам. Кроме того, программы, написанные на Java, должны были работать поверх JVM, что делало программы на Java очень переносимыми, в отличие от программ на C++.

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

  • Поисковые системы в Интернете (например, Google)
  • Механизмы веб-браузера (например, Mozilla Firefox)
  • Системное программное обеспечение (например, операционные системы и драйверы устройств)
  • Разработка игр
  • Программное обеспечение телекоммуникационных систем.

Полный список приложений, написанных с использованием C++, можно найти по этой ссылке, поддерживаемой Бьерном Страуструпом (создателем языка).

Зверь ревет назад

Как объясняется в небольшой книжке C++ Today, опубликованной O'Reilly, распространение мобильных устройств и развитие облачных вычислений вернули вопрос производительности к центральная сцена. По словам авторов книги, производительность на ватт в настоящее время является одним из наиболее важных факторов, влияющих на мобильные устройства. То же самое относится и к облачным компьютерам, которые работают в облачных центрах обработки данных. Эти факторы привели к возрождению интереса к C++ со стороны более широкого сообщества разработчиков.

Чтобы лучше обслуживать новый легион инженеров-программистов, заинтересованных в этом языке, C++ пришлось претерпеть огромные изменения. Изменения были направлены на то, чтобы сделать язык более доступным и менее сложным. Кроме того, в язык были включены новые функции (например, возможности многопоточности и лямбда-выражения), чтобы сделать его более современным.

Такие усилия, направленные на то, чтобы снова сделать C++ популярным, напрямую привели к тому, что теперь широко известно как «Современный C++». Начиная с C++11, в язык было добавлено множество новых отличных функций, что привело к новому виду, которого так жаждало большинство разработчиков. C++14 считался небольшим отладочным выпуском, в то время как в C++17 было добавлено несколько дополнительных функций. язык.

Далее следует краткое обсуждение некоторых новых функций C++, начиная с C++11.

Введите вывод, используя ключевое слово ‘auto’

Вывод типа (или дедукция) является функцией по умолчанию в большинстве современных языков программирования. Например, объявление переменной в Go выглядит так:

x := 10 // x inferred as an integer

Как видно из фрагмента кода, вам не нужно явно объявлять тип переменной «x». Вместо этого компилятор Go сделает это за вас, основываясь на заданном начальном значении.

В «старом» C++ (pre-C++11) тип переменной нужно было объявлять явно, например так:

int x;      // x declared as an integer
int y = 10; // y declared and initialized at the same time

Начиная с C++11 теперь можно использовать вывод типа с помощью ключевого слова auto, как показано ниже:

auto x = 1; // x deduced as an integer

Обратите внимание, что для работы вывода типа переменная должна быть инициализирована.

for Цикл на основе диапазона

Эта функция делает написание циклов for более лаконичным и увлекательным.

В Python цикл for на основе диапазона выглядит так:

for i in range(10):
   print(i)

Вывод кода выше:

0
1
2
3
4
5
6
7
8
9

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

// declare and initialize an array of integers
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 	
for ( int i = 0; i < 10; ++i ) {
     cout << a[i] << endl;
}

Используя цикл for на основе диапазона, приведенный выше код можно переписать, как показано ниже:

int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 	
for ( int i : a ) {
     cout << i << endl;
}

Гораздо лучше и чище, вам не кажется?

Чтобы лучше проиллюстрировать преимущества ключевого слова auto и цикла forloop на основе диапазона, вот еще один пример:

Эта первая версия написана в старом стиле C++.

#include <iostream>
#include <vector>
 	
using namespace std;
 	
int main( int argc, char ** argv ) {
	// Declare and initialize a vector of integers
	vector<int> vi = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	 	       
	// Declare an iterator and loop through 
        // all the vector elements
	for( vector<int>::iterator it = vi.begin(); it < vi.end(); ++it ) {
	   cout << *it << endl;
       }
       return 0;
}

Ниже представлена ​​вторая версия с использованием ключевого слова auto:

#include <iostream>
#include <vector>
 	
using namespace std;
 	
int main( int argc, char ** argv ) {
	// Declare and initialize a vector of integers
	vector<int> vi = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	 	       
	// Type deduction using auto
	for( auto it = vi.begin(); it < vi.end(); ++it ) {
	   cout << *it << endl;
	}
	return 0;
}

Обратите внимание, что теперь нам больше не нужно объявлять тип it в качестве векторного итератора.

Третья версия еще короче и лаконичнее. Здесь мы используем основанный на диапазоне forloop:

#include <iostream>
#include <vector>
 	
using namespace std;
 	
int main( int argc, char ** argv ) {
	// Declare and initialize a vector of integers
	vector<int> vi = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	 	       
	// Range-based for loop
	for ( auto & i : vi ) {
	   cout << i << endl;
	}
	return 0;
}

Вывод для кода выше будет:

1
2
3
4
5
6
7
8
9
10

Auto в шаблонах

Это функция C++17, которая теперь позволяет объявлять нетиповые аргументы шаблона с помощью ключевого слова auto. Это позволяет выводить параметры шаблона в момент создания экземпляра, а не указывать их явно, как показано ниже:

template <auto V> void somefunc() { } // V is some constant (const) value
somefunc<20>();    // 'int' is deduced

Раньше вам нужно было написать что-то вроде этого:

template <typename T, V> void somefunc() { }
somefunc<int, 20>();

if constexpr (выражение)

Это еще одна новая функция в C++17, которую можно рассматривать как версию C++ времени компиляции if.

Это позволяет компилировать блоки кода, только если constexpr оценивается как true во время компиляции:

if constexpr(is_integer ...) { // execute integerstuff }
else if constexpr(is_floating_point ...) { // execute floatingpointstuff }
else { // NaN; }

Для получения дополнительной информации о многих других новых функциях C++ перейдите по этой ссылке, поддерживаемой Standard C++ Foundation (isocpp.org).

Два самых популярных проекта, выполненных с использованием современного C++:

  • Seastar: платформа C++ с открытым исходным кодом для высокопроизводительных серверных приложений, которая составляет основу ScyllaDB, базы данных NoSQL, которую рекламируют как Cassandra следующего поколения.
  • OSv: облачная операционная система, полностью написанная на C++.

Вывод

Так же, как часто говорят, что Лев никогда не спит, C++ никогда не спит. И как только мы подумали, что зверь задремал, он взревел в ответ, ко всеобщему удовольствию (и удивлению!)

Использованная литература: