C++ Academy
11.4K subscribers
209 photos
77 videos
246 links
По всем вопросам- @haarrp
Download Telegram
🖥 Полезная подборка антипаттернов C++

60 антипаттернов и вредных советов для С++ программиста с подробными пояснениями.
В пояснениях можно найти интересную информацию.
В некоторых местах разбираются неочевидные нюансы C++; про них будет интересно почитать и опытным разработчикам.

📎 Подборка

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥 50 годных сайтов с ресурсами по изучению C++ (и C)

🟡https://www.w3schools.com/cpp/ — Туториал по C++ от W3Schools
🟡https://cppreference.com/ — Справочник по C++
🟡https://www.onlinegdb.com/ — Мой любимый компилятор и дебаггер C++
🟡https://www.hotscripts.com/category/c-cpp/scripts-programs/ — Сотни программ и скриптов на C и C++, всё удобненько разложено по категоориям
🟡https://sourceforge.net/directory/ — Больше 75К проектов, написанных на C/C++
🟡https://www.daniweb.com/tags/c/code — Полезные фрагменты кода
🟡https://programmersheaven.com/categories/candcpp Ресурсы для прокачивания плюсов
🟡https://www.codecogs.com/ CodeCogs — это совместная библиотека с открытым исходным кодом, числовые компоненты которой написаны на C/C++.
🟡https://developers.google.com/code-search/ — Поиск кода с помощью Google
🟡https://www.cis.temple.edu/~ingargio/cis71/code/ — Список простых C-шных программ, с них можно начинать изучение
🟡https://www.codeproject.com/?cat=2 — Много полезностей по C/C++

Остальные ссылки не влезают в пост, поэтому продолжение тут

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
TCP/IP сети и `Boost.Asio` — объяснение от Ричарда Томсона

Boost.Asio — это кроссплатформенная библиотека C++ для программирования сетей и низкоуровневого ввода-вывода, которая предоставляет разработчикам последовательную асинхронную модель с использованием современного подхода C++.

В этом видео Ричард Томсон покажет, как работать с Boost.Asio и TCP/IP. Расскажет, как реализовать клиент NNTP (Network News Transport Protocol) с помощью Boost.Asio. NNTP — это линейно-ориентированный протокол для чтения новостных статей usenet. Это даст нам представление обо всех типичных проблемах, связанных с сетевыми приложениями TCP/IP:
🔘Как преобразовать имя хоста в IP-адрес?
🔘Как установить долговременное соединение с сервером NNTP?
🔘Как обрабатывать произвольно большие объемы данных с NNTP-сервера, которые поступают асинхронно?
🔘Как координировать ввод данных пользователем с вводом/выводом NNTP?
🔘Как справляться с неожиданными сетевыми ошибками?

Очень полезное видео, рекомендую
Youtube

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Чем отличаются ссылки от указателей в С++

В чем принципиальное отличие ссылки от указателя в С++? Какие ограничения есть у первых, а какие у вторых?

Вот некоторые из отличий::
🔘Нельзя объявить массив ссылок.
🔘У ссылки нет адреса.
🔘Существует арифметика указателей, но нет арифметики ссылок.
🔘Указатель может иметь «невалидное» значение с которым его можно сравнить перед использованием.

🔘Если вызывающая сторона не может не передать ссылку, то указатель может иметь специальное значение nullptr:
void f(int* num, int& num2)
{
if(num != nullptr) // if nullptr ignored algorithm
{
}
// can't check num2 on need to use or not
}


🔘Ссылка не обладает квалификатором const
#include <iostream>
int main()
{
std::cout << "Hello, world!\n";

const int v = 10;
//int& const r = v; // Ошибка
const int& r = v;

enum
{
is_const = std::is_const<decltype(r)>::value
};

if(!is_const)
std::cout << "const int& r is not const\n";
else
std::cout << "const int& r is const\n";
}


@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥 Супер-годный контент по работе с корутинами в С++

Напомню самую основную инфо по корутинам:
*️⃣Для объявления корутины используется ключевое слово co_return. Оно позволяет вернуть значение из корутины в вызывающий код.
*️⃣Для ожидания результата работы другой корутины используется ключевое слово co_await. Оно приостанавливает выполнение текущей корутины и передает управление вызывающему коду. Когда результат работы другой корутины готов, выполнение текущей корутины возобновляется.
*️⃣Для создания дескриптора корутины используется функция std::coroutine_handle. Она принимает указатель на функцию-корутину и возвращает объект класса std::coroutine_handle.

Ну а в этой статье ты найдёшь подробное описание разных нюансов и подводных камней, в процессе автор пишет асинхронный веб-клиент

📎 Статья

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
🖥 Свежая библиотека Intel x86-simd-sort 5.0

Относительно недавно состоялся релиз открытой библиотеки Intel x86-simd-sort 5.0, в которой представлен новый API для сортировки пользовательских объектов C++ с помощью object_qsort.

Согласно тестам разработчиков проекта, новая поддержка сортировки пользовательских объектов C++ может быть в 4-5 раз быстрее, чем использование std::sort в системах AVX-512, но в конечном итоге влияние на производительность будет варьироваться в зависимости от используемых задач.

Также в выпуске x86-simd-sort 5.0 добавлен новый API-интерфейс keyvalue_qsort для сортировки массивов, представляющих пары «ключ-значение», и этот новый API тоже работает намного быстрее.

В версии x86-simd-sort 5.0 добавлена поддержка AVX2 для методов argosrt и argselect. Эти дополнения AVX2 уже вошли в исходную версию NumPy для NumPy 2.0, причем эта библиотека Python была одним из первых проектов, который добавил поддержку высокопроизводительной библиотеки Intel.

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Имплементация print() на C++

🌟 Интересная статья о том, как реализовать Python-функцию print() на C++.
Автор создал C++ версию print() для отладки, назвал её cpp_dump(), и параллельно создал библиотеку cpp-dump для управления цветов и другими параметрами отображения объектов.

Функция cpp_dump() выводит разные объекты/переменные в строковом представлении, автоматически делает отступы для соответствия максимальной ширине строки.
cpp_dump() поддерживает различные другие типы, включая std::multimap и std::complex.

Можно настраивать цвета отображаемых при помощи cpp_dump() объектов.

📎 Статья

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Бьёрн Страуструп ответил на призыв Белого дома переходить с C++ на языки с безопасностью памяти

26 февраля 2024 года Белый дом США выпустил призыв переходить на языки программирования с безопасным доступом к памяти типа Rust. Бьёрн Страуструп, создатель языка C++, в комментарии для издания InfoWorld ответил на критику его творения.

Язык ассемблера и языки с низким уровнем абстракций по типу C и C++ поддерживают произвольную арифметику указателей с реальными адресами памяти без автоматической проверки границ, что допускает лёгкий «выстрел в ногу». Исторически сложилось, что на таких языках пишут низкоуровневые компоненты компьютерных систем: прошивки микроконтроллеров, операционные системы, критически важные и высоконагруженные приложения.

Аргументация Страструпа схожа с использованной ранее в ответе на призывы АНБ в 2022 году:
C++ — это не C. Бьёрн напомнил, что улучшение безопасности было задачей C++ с первого дня: «Просто попробуйте сравнить С эпохи Кернигана и Ритчи с самым ранним C++ и ранний C++ с современным C++».

C++ далеко продвинулся с 1979 года. «Эта эволюция кратко изложена в моём выступлении 2023 года на CppCon» — указал Страуструп. Он напомнил, что качественный код на С++ пишут с применением концепции RAII, контейнеров и умных указателей, а не «традиционной мешанины указателей C».

Понимание безопасности не всегда корректно. Как жалуется Страуструп, из миллиардов строчек кода на C++ лишь небольшая доля полностью следует современным рекомендациям безопасности, а сообщество по-разному оценивает, какие аспекты безопасности важны.

📎 Читать подробнее

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥🖥 Использование static в C++ и C#: методы, переменные, классы

Статический метод – это как универсальный инструмент, который работает без необходимости создавать объект класса.

Представим, что вы разрабатываете приложение для калькулятора. В нём есть разные математические операции, такие как сложение, вычитание, умножение и деление. Однако, есть одна операция, которая не требует данных о конкретном экземпляре калькулятора для выполнения — это, например, операция вычисления квадратного корня. Для таких операций идеально подходят статические методы.
public class Calculator {

// Статический метод для вычисления квадратного корня
public static double squareRoot(double number) {
return Math.sqrt(number);
}

// Обычный метод для сложения
public double add(double number1, double number2) {
return number1 + number2;
}
}


Для вызова статического метода не нужно создавать объект класса Calculator. Вы можете просто вызвать метод напрямую через имя класса:
double result = Calculator.squareRoot(16); // Возвращает 4.0


Основы и принципы работы static
Важно понимать, что статические переменные и методы хранятся в специальной области памяти (например, в .data или .bss для C++), и их значения или состояния сохраняются на протяжении всего времени работы программы. Это делает их идеальными для хранения глобальных настроек или выполнения операций, которые не зависят от состояния объектов.

Различия между static в C++ и C#
— Static в C++ часто используется для определения глобальных переменных, статических членов класса и функций, ограниченных областью видимости файла. Это позволяет избежать конфликтов имен и обеспечивает более чистую структуру кода.

— Static в C# имеет более широкое применение, включая статические классы, которые не могут быть инстанциированы и содержат только статические члены. Это делает C# статические классы идеальными для создания утилит и вспомогательных методов.

📎 Читать подробнее

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Предупреждение об арифметическое переполнение

▶️Итак, при запуске этого кода:
#include <iostream>
#include <vector>

int main() {
std::vector<int> a{0,1,2,3,4,5};
int b = 0;
std::cout << a[b + 1] << std::endl; // подчеркивает 'b+1'
return 0;
}

возникает проблема:
Арифметическое переполнение: использование оператора "+" на байтовом значении 4 и приведение результата к байтовому значению 8. Приведите значение к более широкому типу перед вызовом оператора "+", чтобы избежать переполнения (io.2)


Почему возникает такое предупреждение?


▶️В общем, в этом случае суть предупреждения такая: для индексации вектора на 64-битной платформе используется 64-битное беззнаковое целое, но выражение b+1 имеет тип int. Если предположить, что в b будет максимальное значение, представимое типом int, то получим UB.

Решение: привести хотя бы один из операндов к 64-битному типу.

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

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Некоторые тонкости генерации случайных чисел в C++

C и C++ имеют свои собственные встроенные генераторы случайных чисел. Они реализованы в двух отдельных функциях, которые находятся в заголовочном файле cstdlib:

srand() устанавливает передаваемое пользователем значение в качестве стартового. srand() следует вызывать только один раз — в начале программы (обычно в верхней части функции main())

rand() генерирует следующее случайное число в последовательности. Оно будет находиться в диапазоне от 0 до RAND_MAX (константа в cstdlib, значением которой является 32767).

Вот пример программы, в которой используются обе эти функции:
#include <iostream>
#include <cstdlib> // для функций rand() и srand()

int main()
{
srand(4541); // устанавливаем стартовое значение - 4 541

// Выводим 100 случайных чисел
for (int count=0; count < 100; ++count)
{
std::cout << rand() << "\t";

// Если вывели 5 чисел, то вставляем символ новой строки
if ((count+1) % 5 == 0)
std::cout << "\n";
}
}

// 14867 24680 8872 25432 21865
// ...



Рандомные числа в C++ 11

В C++ 11 добавили тонну нового функционала для генерации случайных чисел, включая алгоритм Вихрь Мерсенна, а также разные виды генераторов случайных чисел (например, равномерные, генератор Poisson и пр.). Доступ к ним осуществляется через подключение заголовочного файла random.

Вот пример генерации случайных чисел в C++11 с использованием Вихря Мерсенна на картинке.

Вихрь Мерсенна генерирует случайные 32-битные целые числа unsigned (а не 15-битные целые числа, как в случае с rand()), что позволяет использовать гораздо больший диапазон значений.
Существует также версия (std::mt19937_64) для генерации 64-битных целых чисел unsigned

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Дискуссия об использовании языка C++ для разработки ядра Linux

В списке рассылки разработчиков ядра Linux возобновилось начатое шесть лет назад обсуждение перспектив использования современного кода на C++ в ядре Linux, помимо нынешнего применения языка Си с ассемблерными вставками и продвижения языка Rust. Изначально тема разработки ядра на C++ была поднята в 2018 году инженером из Red Hat, который первого апреля в качестве шутки опубликовал набор из 45 патчей для использования шаблонов, наследуемых классов и перегрузки функций C++ в коде ядра.

С инициативой продолжения обсуждения выступил Ганс Питер Анвин, один из ключевых разработчиков ядра в компании Intel. По мнению Анвина, который является автором многочисленных макросов и ассемблерных вставок в ядре, с 1999 года языки C и C++ значительно продвинулись вперёд в своём развитии и язык C++ стал лучше, чем С, подходить для разработки ядра операционных систем.

Возможности, для которых ещё недавно приходилось привлекать специфичные GCC-расширения, теперь легко реализовать на стандартном C++, и во многих случаях использование C++ позволит улучшить инфраструктуру без глобального изменения кода. В качестве минимальной упоминается использование спецификации C++14, которая включает необходимые средства метапрограммирования, а в качестве желаемой - использование спецификации C++20, в которой появилась поддержка концепций, способных исключить появление многих ошибок.

Анвин считает, что C++ более предпочтителен, чем Rust, так как последний существенно отличается от языка С по синтаксису, непривычен для текущих разработчиков ядра и не позволяет постепенно переписывать код (в случае языка С++ можно по частям переводить код с языка C, так как С-код можно компилировать как C++). В поддержку использования С++ в ядре также выступили Иржи Слаби (Jiri Slaby) из компании SUSE и Дэвид Хауэллс (David Howells) из Red Hat.

📎 Читать подробнее

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Почему считается что неправильно писать while (!input_stream.eof())?

▶️В разных источниках говорят что использование std::istream::eof() - это признак плохого кода и что в частности неправильно писать:
while (!input_stream.eof()) {
input_stream >> value;
process(value);
}

Что в этом коде не так? Как писать правильно?


▶️Проблема std::istream::eof() в том, что он выставляется только после выполнения какой-либо операции чтения. Поэтому происходит следующее:
std::ifstream input_stream("empty_file.txt"); // Открываем пустой файл
if (!input_stream.eof()) { // eof() == false, т.к. мы еще ничего не читали
int value;
input_stream >> value; // Пытаемся читать число, а его там нет.
// Здесь eof() == true, но мы это не проверяем.
std::cout << value; // Выведется 0.
}

Так что если и вызывать eof(), то это надо делать после операции чтения.

Однако, объекты std::istream умеют преобразовываться в bool, а каждая операция чтения возвращает ссылку на std::istream. Поэтому идиоматичный код выглядит следующим образом:
while (input_stream >> value) {
process(value);
}


Или для строки:
std::string str;
while (std::getline(input_stream, str)) { ... }


Или сразу для нескольких значений:
while (input_stream >> value1 >> value2) { ... }

Здесь если при чтении value1 произойдет ошибка, то все последующие операции чтения (т.е. value2) будут игнорироваться, по этому можно читать сразу несколько значений сразу, и уже потом проверять состояние std::istream.

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Некоторые тонкости генерации случайных чисел в C++

C и C++ имеют свои собственные встроенные генераторы случайных чисел. Они реализованы в двух отдельных функциях, которые находятся в заголовочном файле cstdlib:

srand() устанавливает передаваемое пользователем значение в качестве стартового. srand() следует вызывать только один раз — в начале программы (обычно в верхней части функции main())

rand() генерирует следующее случайное число в последовательности. Оно будет находиться в диапазоне от 0 до RAND_MAX (константа в cstdlib, значением которой является 32767).

Вот пример программы, в которой используются обе эти функции:
#include <iostream>
#include <cstdlib> // для функций rand() и srand()

int main()
{
srand(4541); // устанавливаем стартовое значение - 4 541

// Выводим 100 случайных чисел
for (int count=0; count < 100; ++count)
{
std::cout << rand() << "\t";

// Если вывели 5 чисел, то вставляем символ новой строки
if ((count+1) % 5 == 0)
std::cout << "\n";
}
}

// 14867 24680 8872 25432 21865
// ...



Рандомные числа в C++ 11

В C++ 11 добавили тонну нового функционала для генерации случайных чисел, включая алгоритм Вихрь Мерсенна, а также разные виды генераторов случайных чисел (например, равномерные, генератор Poisson и пр.). Доступ к ним осуществляется через подключение заголовочного файла random.

Вот пример генерации случайных чисел в C++11 с использованием Вихря Мерсенна на картинке.

Вихрь Мерсенна генерирует случайные 32-битные целые числа unsigned (а не 15-битные целые числа, как в случае с rand()), что позволяет использовать гораздо больший диапазон значений.
Существует также версия (std::mt19937_64) для генерации 64-битных целых чисел unsigned

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 AdaptiveCpp: универсальный SYCL-компилятор с рекордной производительностью

На днях вышла новая версия компилятора AdaptiveCpp 24.02, ранее известного под названиями hypSYCL и Open SYCL. Этот компилятор на основе C++ предназначен для создания программного кода, работающего на различных процессорах и графических процессорах ведущих производителей. Возможности такого программирования обеспечиваются стандартами SYCL и параллелизмом C++.

Версия AdaptiveCpp 24.02 принесла ряд улучшений в работу компилятора. Разработчики отмечают, что благодаря этим улучшениям их продукт стал одним из лучших (а во многих случаях и самым лучшим) компилятором SYCL в мире с точки зрения эффективности использования аппаратных ресурсов.

Тесты показали, что AdaptiveCpp 24.02 работает значительно быстрее предыдущей версии 23.10 и, как правило, превосходит по производительности стек SYCL от Intel, одного из крупнейших производителей в этой области.

Одной из ключевых особенностей новой версии является отказ от необходимости указывать конкретные цели компиляции для создания исполняемого файла. Теперь простая команда компиляции acpp -o test -O3 test.cpp позволяет создать бинарный файл, который будет работать на GPU от Intel, NVIDIA и AMD, что делает AdaptiveCpp единственным в мире компилятором SYCL, способным генерировать такие универсальные исполняемые файлы.

Кроме того, в новой версии появился новый JIT-компилятор для CPU, который обеспечивает более высокую производительность по сравнению со старым компилятором на основе OpenMP.
AdaptiveCpp 24.02 также предлагает кэширование ядер на диске, автоматическую специализацию ядер во время выполнения и другие улучшения.

🖥 Дополнительные сведения о выпуске AdaptiveCpp 24.02 и ссылки для скачивания доступны на GitHub

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Как выстрелить себе в ногу в C++

Полезная статья о том, что с C++ нужно быть поаккуратнее.
В статье освещается множество важных нюансов, в частности:
Неинициализированные переменные
Подозрительный #define
Ошибки с функцией free
Ошибки с оператором delete
Функции без возвращаемого значения
Работа с исключениями
Сравнения с беззнаковыми переменными
Опасные указатели

📎 Статья

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Жизненная проблема в C++: правильное использование проверки конца файла

При использовании в C++ кода
while(!file.eof())
{
// Чтение из файла
}

получаются неприятности - лишняя считанная строка, например. Почему? Как правильно проверить, что достигнут конец файла?

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

Лучше для этого использовать цикл for и в заголовке выполнять само чтение с проверкой:
for(int n; file >> n; ) 
{
// Обработка считанного значения n
}

if (file.bad())
std::cout << "Ошибка ввода-вывода при чтении\n";
else if (file.eof())
std::cout << "Достигнут конец файла\n";
else if (file.fail())
std::cout << "Неверный формат данных\n";


@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
🖥 Autocheck — проект на базе LLVM/Clang для проверки кода C/C++ на соответствие стандарту AUTOSAR

Не так давно года Syrmia (занимается разработкой встроенного ПО) представила Autocheck.
Это открытый проект парсера на базе LLVM/Clang для проверки кода C и C++ на предмет оценки его пригодности для работы внутри транспортных механизмов (автомобилей и прочего) и других критически важных для безопасности технических сред в рамках соответствия требованиям стандарта AUTOSAR (AUTOmotive Open System ARchitecture) C++14.

Также Autocheck доступен в качестве плагина для VSCode. В этом случае Autocheck отображает нарушения правил AUTOSAR C++ в режиме реального времени по мере того, как пользователь вводит код. Каждое нарушение выделяется в редакторе, а сообщение о нарушенном правиле отображается при наведении курсора на код, а также на панели Problems.

🖥 Исходные коды проекта Autocheck выложены на GitHub под лицензией Apache License 2.0

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Интеграция HTML/CSS UI в разработку C++ приложений

▶️Итак, если вам требуется быстро интегрировать веб-интерфейс в приложение, написанное на C++, используйте Chromium Embedded Framework (CEF). Подключив экземпляр CEF к вашему проекту, загрузите HTML-документ и запустите цикл обработки событий CEF. Эта гибридная схема разработки позволит вам реализовать интерфейс на HTML/CSS, оставив при этом бекенд на C++. Выглядеть это может как-то так:
#include "include/cef_app.h"

int main(int argc, char* argv[]) {
CefMainArgs main_args(argc, argv);
CefSettings settings;

// выполняем инициализацию
CefInitialize(main_args, settings, nullptr, nullptr);

// создаем окно с UI
CefWindowInfo window_info;
CefBrowserHost::CreateBrowser(window_info, new SimpleHandler(), "file:///your_ui.html", CefBrowserSettings(), nullptr);

// цикл обработки сообщений
CefRunMessageLoop();

// Cef для окончания работы
CefShutdown();
}

Замените "file:///your_ui.html" на путь к вашему HTML-файлу. Вуаля! Ваш интерфейс на HTML/CSS уже встроен в приложение на C++.


▶️CEF зарекомендовал себя как надёжное решение для интеграции Chromium в приложения на C++, однако есть и другие варианты, которые стоит рассмотреть:

Electron: Объединяет Chromium и Node.js, позволяя использовать JavaScript для построения настольных приложений.

Ultralight: Идеально подходит для приложений на OpenGL или DirectX, где важна эффективность рендеринга HTML.

Qt WebEngine: Дает доступ к возможностям Qt с поддержкой интеграции веб-контента.

Sciter: Имеет компактный движок для работы с HTML/CSS, поддерживающий такие возможности, как SVG и WebSocket.

Awesomium, движки на базе WebKit или Gecko: Предлагают функциональность, схожую с CEF, однако с некими уникальными отличиями.


▶️При выборе фреймворка обратите внимание на его уровень зрелости, поддержку со стороны сообщества и доступность документации.

📎 Читать подробнее

@cpluspluc
Please open Telegram to view this post
VIEW IN TELEGRAM