C++ Academy
По всем вопросам- @workakkk РКН: clck.ru/3FmxJF #VRHSZ
Show more📈 Analytical overview of Telegram channel C++ Academy
Channel C++ Academy (@cpluspluc) in the Russian language segment is an active participant. Currently, the community unites 15 543 subscribers, ranking 8 057 in the Technologies & Applications category and 41 955 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 15 543 subscribers.
According to the latest data from 14 September, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by 74 over the last 30 days and by -2 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 15.66%. Within the first 24 hours after publication, content typically collects 6.73% reactions from the total number of subscribers.
- Post reach: On average, each post receives 2 434 views. Within the first day, a publication typically gains 1 046 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 21.
- Thematic interests: Content is focused on key topics such as c++, github, linux, api, архитектура.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“По всем вопросам- @workakkk
РКН: clck.ru/3FmxJF
#VRHSZ”
Thanks to the high frequency of updates (latest data received on 15 September, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)
После препроцессора это превращается сразу в несколько функций:
- sys_write
- __se_sys_write
- __do_sys_write
Одна строка описывает системный вызов, а C-препроцессор через макросы и token pasting собирает остальную обвязку автоматически.
Именно поэтому код ядра Linux часто выглядит коротко, пока не начнёшь разворачивать макросы.CRC16(key) % 16384
Но есть важный трюк — hash tags.
Если ключ содержит часть в фигурных скобках, Redis хеширует только содержимое внутри {}:
{user100}:cart
{user100}:orders
Оба ключа будут вычислены по user100, поэтому попадут в один и тот же hash slot и, соответственно, на одну ноду.
Это нужно для multi-key операций в cluster mode.
Именно поэтому такие конструкции позволяют нормально использовать:
- MGET
- MSET
- транзакции
- Lua-скрипты с несколькими ключами
На уровне кода Redis сначала ищет {, затем }, и если внутри есть непустая строка — хеширует только её.
Небольшая деталь синтаксиса, которая на самом деле решает важную проблему распределённых операций в Redis Cluster.std::map<std::string, ...> не обязан создавать временный std::string при каждом поиске
Если ключ уже приходит как std::string_view, можно использовать transparent comparator:
std::map<std::string, int, std::less<>> status_codes{
{"not_found", 404},
{"timeout", 504}
};
std::string_view key = "timeout";
auto match = status_codes.find(key);FILE* можно обернуть в std::unique_ptr с собственным обработчиком освобождения:
#include <cstdio>
#include <memory>
struct FileCloser {
void operator()(std::FILE* file) const noexcept {
std::fclose(file);
}
};
using File = std::unique_ptr<std::FILE, FileCloser>;
Использование внутри функции:
File file{std::fopen("data.txt", "r")};
if (!file) {
return;
}
// Передаём FILE* в функции C-библиотеки
int ch = std::fgetc(file.get());
Когда file выйдет из области видимости, unique_ptr вызовет fclose. Это работает при обычном завершении функции, раннем return и раскрутке стека при исключении.
Так устроен RAII: время жизни ресурса связано со временем жизни объекта. Если fopen вернул nullptr, обработчик освобождения вызван не будет.header → отдельно payload → отдельноможно сделать один непрерывный блок памяти:
+----------------+ | struct msg | | len | +----------------+ | payload data[] | +----------------+Код:
struct msg {
uint32_t len;
uint8_t data[];
};
struct msg *m = malloc(sizeof(*m) + n);
Один malloc() → один блок памяти → один free().
Почему это любят в системном коде:
✅ меньше аллокаций
✅ лучше работа с CPU cache
✅ проще сериализация
✅ нет лишних указателей и разрозненных данных
Такой подход используется в низкоуровневом коде: ядрах, драйверах, сетевых стеках.
До C99 часто писали:
uint8_t data[1];
и вручную обходили ограничения языка.
Теперь data[] — официальный способ сказать:
«После структуры здесь будет динамический массив данных».
Маленькая особенность C, которая помогает писать быстрый код на уровне ядра.\0. Из-за этого strlen() каждый раз проходит весь буфер, а хранить произвольные бинарные данные становится неудобно.
Поэтому Redis использует собственную структуру SDS — Simple Dynamic Strings.
В памяти она выглядит примерно так:
[len][alloc][flags][данные...\0]
↑
sds
Перед самими данными Redis хранит метаданные:
- len — текущую длину;
- alloc — размер выделенной памяти;
- flags — тип заголовка.
Благодаря этому длина строки определяется за O(1), а свободное место известно заранее. При добавлении данных Redis не обязан каждый раз заново вычислять размер и перевыделять память.
SDS также остаётся совместимой со многими функциями C: указатель ведёт прямо на буфер, а в конце всё равно находится \0.
Но Redis не зависит от этого терминатора — длина хранится отдельно. Поэтому внутри строки могут находиться нулевые байты, изображения, сериализованные объекты и другие бинарные данные.
Важный нюанс: структура sdshdr из старых примеров сегодня упрощена. Современный Redis выбирает компактный заголовок sdshdr5, sdshdr8, sdshdr16, sdshdr32 или sdshdr64 в зависимости от размера строки.
Небольшой заголовок перед буфером решил сразу три проблемы: быстрое получение длины, безопасную работу с бинарными данными и эффективное расширение строк.
Источник:
https://redis.io/docs/latest/operate/oss_and_stack/reference/internals/internals-sds/
https://github.com/redis/redis/blob/unstable/src/sds.hO(n), но неудачный выбор опорного элемента может превратить поиск k-го элемента в O(n²).
В 1973 году Блум, Флойд, Пратт, Ривест и Тарьян предложили алгоритм median of medians, который гарантирует линейное время даже в худшем случае.
Идея:
1. Разделить массив на группы по 5 элементов.
2. Найти медиану каждой группы.
3. Рекурсивно найти медиану полученных медиан.
4. Использовать её как pivot для Quickselect.
int mom_pivot(int *arr, int n)
{
if (n <= 5) {
sort(arr, n);
return arr[n / 2];
}
int medians[(n + 4) / 5];
for (int i = 0; i < n; i += 5) {
int len = (n - i < 5) ? n - i : 5;
sort(arr + i, len);
medians[i / 5] = arr[i + len / 2];
}
return mom_pivot(medians, (n + 4) / 5);
}
Такой pivot не обязательно будет настоящей медианой массива, но он гарантированно не окажется слишком близко к краю. После разбиения отбрасывается достаточно большая часть элементов, поэтому рекурсия не деградирует.
Итоговая сложность поиска:
Средний случай: O(n)
Худший случай: O(n)
Дополнительная память: зависит от реализации
На практике randomized Quickselect часто быстрее из-за меньших констант. Median of medians нужен там, где важна строгая гарантия времени: real-time системы, adversarial input и библиотеки с предсказуемой производительностью.1 - байт загружается
- 0 - вместо него ставится ноль
Самое интересное начинается, когда маска полностью нулевая:
#include <x86intrin.h>
void f(const char *p) {
_mm512_maskz_loadu_epi8(0, p);
}
При нулевой маске память фактически не читается, а результатом становится 512-битный вектор из нулей.
То есть значение p в таком случае не влияет на результат, а компилятор при оптимизации вообще может удалить весь вызов.
Хороший пример того, насколько необычно работают masked-load инструкции в AVX-512.LPPROC_THREAD_ATTRIBUTE_LIST, который нужен при расширенном создании процессов и потоков.
Проблема в API простая:
- сначала нужно отдельно узнать размер буфера
- потом вручную выделить память
- вызвать InitializeProcThreadAttributeList
- после работы обязательно вызвать DeleteProcThreadAttributeList
- и только потом освободить сам буфер
Chen предлагает обернуть всё это в RAII через WIL, чтобы очистка происходила автоматически.
Из интересного:
- отдельный helper для освобождения списка
- безопасное получение нужного размера
- разбор того, почему CTAD здесь не помогает
- перегрузки через SFINAE, чтобы не ловить неоднозначность с int
- возможность сразу предзаполнить список атрибутами
- можно заранее оставить место под дополнительные атрибуты, которые добавятся позже
В итоге работа с LPPROC_THREAD_ATTRIBUTE_LIST становится заметно аккуратнее и меньше похожа на ручной Win32-ритуал с кучей cleanup-кода.
https://devblogs.microsoft.com/oldnewthing/20260813-00/?p=112611this_cpu_inc(var) превращается в одну инструкцию incl, которая работает с областью данных текущего CPU через GS.
Что это даёт:
* нет общего lock
* нет постоянной конкуренции между ядрами
* инкремент выполняется локально для текущего CPU
* операция получается быстрой и дешёвой
Идея мощная: если данные можно разделить по CPU, не нужно синхронизировать каждый маленький апдейт между всеми ядрами.
Так ядро экономит огромное количество лишней блокировки там, где код выполняется постоянно.curl работает на миллиардах устройств и поставляется почти везде:
* macOS
* основные Linux-дистрибутивы
* Windows 10 и новее
* серверы
* контейнеры
* embedded-системы
* CI/CD пайплайны
Ирония в том, что многие пользуются curl каждый день, даже не думая об этом.
Одна маленькая CLI-утилита стала невидимой инфраструктурой интернета.
Вот так выглядит настоящий open source: без хайпа, без миллиардных раундов, но с кодом, который держит половину мира.