Если views::filter решает, какие элементы обработать, то
views::transform — во что их превратить. Никакого копирования: это такая же ленивая обёртка над данными.🌸 Базовое использование
#include <ranges>
#include <vector>
#include <string>
namespace views = std::views;
std::vector<std::string> words = {"hello", "world", "cpp"};
// Получаем длины слов
auto lengths = words | views::transform([](const std::string& s) {
return s.size();
});
// При итерации: 5, 5, 3
Лямбда применяется к каждому элементу в момент итерации — ни раньше, ни позже.
🍪 Трансформация с изменением типа
transform не обязан возвращать тот же тип. Из string можно получить size_t, из double — int, из структуры — одно из её полей:// Верхний регистр (#include <cctype>)
auto upper = words | views::transform([](std::string s) {
for (char& c : s) c = std::toupper(c);
return s;
});
// При итерации: "HELLO", "WORLD", "CPP"
Обратите внимание: здесь s принимается по значению — это намеренная копия, которую мы модифицируем.
🍀 filter + transform — классика
Главная сила адаптеров — в их цепочке. Сначала отсеиваем ненужное, потом преобразуем то, что осталось:
struct Employee {
std::string name;
double salary;
bool is_active;
};
std::vector<Employee> employees = {
{"Алиса", 80000, true},
{"Борис", 95000, false},
{"Виктор", 72000, true},
{"Галина", 110000, true},
};
// Имена активных сотрудников с зарплатой выше 75 000
auto high_earners = employees
| views::filter([](const Employee& e) { return e.is_active; })
| views::filter([](const Employee& e) { return e.salary > 75000; })
| views::transform([](const Employee& e) { return e.name; });
for (const auto& name : high_earners) {
std::cout << name << "\n"; // Алиса, Галина
}Весь конвейер ленив: ни одна лямбда не вызывается, пока не начнётся итерация.
🌱 pipe-синтаксис vs явный тип
auto v1 = words | views::transform([](const std::string& s) { return s.size(); });
auto v2 = std::ranges::transform_view{words, [](const std::string& s) { return s.size(); }};🍙 Материализация в вектор
transform_view — не контейнер. Чтобы получить std::vector, нужно явно материализовать:// C++23
auto vec = words | views::transform([](const std::string& s) { return s.size(); })
| std::ranges::to<std::vector>();
// C++20
std::vector<size_t> vec(lengths.begin(), lengths.end());
// UB — возвращается ссылка на временный объект
auto bad = words | views::transform([](const std::string& s) -> const std::string& {
std::string upper = s;
return upper; // dangling reference!
});
// Правильно — возвращаем по значению
auto ok = words | views::transform([](const std::string& s) {
std::string upper = s;
for (char& c : upper) c = std::toupper(c);
return upper;
});
📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#константная_правильность
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰4👍2🤔2🥱1
🍙 views::take и views::drop — срезы в C++
Если views::transform превращает элементы, то
🌸 views::take — первые N элементов
Лямбда не нужна — достаточно числа. Адаптер остановит итерацию сам, как только наберёт нужное количество.
🍪 take_while — берём пока условие истинно
В отличие от
🍀 views::drop — пропустить первые N элементов
❗️ Важный нюанс:
🌱 Срез в середине: drop + take
Комбинируя два адаптера, получаем аналог Python-срезов:
Весь конвейер по-прежнему ленив: элементы не вычисляются до начала итерации.
🍙 Связка с filter и transform
❌ Ловушка: drop на бесконечном диапазоне
🐸 Продолжение следует...
📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#константная_правильность
Если views::transform превращает элементы, то
views::take и views::drop управляют тем, сколько элементов обработать. Та же ленивая логика, никакого лишнего копирования.🌸 views::take — первые N элементов
#include <ranges>
#include <vector>
namespace views = std::views;
std::vector<int> v = {10, 20, 30, 40, 50};
auto first_three = v | views::take(3);
// При итерации: 10, 20, 30
Лямбда не нужна — достаточно числа. Адаптер остановит итерацию сам, как только наберёт нужное количество.
🍪 take_while — берём пока условие истинно
auto while_lt_40 = v | views::take_while([](int x) { return x < 40; });
// При итерации: 10, 20, 30В отличие от
take(n), здесь количество элементов заранее неизвестно — решает предикат.🍀 views::drop — пропустить первые N элементов
auto skip_two = v | views::drop(2);
// При итерации: 30, 40, 50
// drop_while — пропускаем пока условие истинно
auto after_twenties = v | views::drop_while([](int x) { return x <= 20; });
// При итерации: 30, 40, 50
drop_while проверяет предикат только до первого несовпадения, а затем отдаёт все оставшиеся элементы подряд — даже те, что снова удовлетворили бы условию. Это не фильтр — это одноразовый пропуск.🌱 Срез в середине: drop + take
Комбинируя два адаптера, получаем аналог Python-срезов:
// Элементы с индекса 1 по 3 включительно (аналог v[1:4])
auto slice = v | views::drop(1) | views::take(3);
// При итерации: 20, 30, 40
Весь конвейер по-прежнему ленив: элементы не вычисляются до начала итерации.
🍙 Связка с filter и transform
struct Employee {
std::string name;
double salary;
bool is_active;
};
std::vector<Employee> employees = { /* ... */ };
// Топ-2 активных сотрудника по имени
auto top_two = employees
| views::filter([](const Employee& e) { return e.is_active; })
| views::transform([](const Employee& e) { return e.name; })
| views::take(2);❌ Ловушка: drop на бесконечном диапазоне
// OK — take ограничивает бесконечный iota
auto ok = std::views::iota(1) | std::views::take(5);
// 1, 2, 3, 4, 5
// OK — drop сам по себе безопасен, view создаётся без проблем
auto dropped = std::views::iota(1) | std::views::drop(3);
// ОПАСНО — итерирование без терминатора зависнет навсегда
for (auto x : dropped) { /* никогда не остановится */ }
drop на бесконечном диапазоне создаётся без проблем. Опасность — в цикле без ограничителя. Всегда добавляйте take или аналог, если диапазон потенциально бесконечен.📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#константная_правильность
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤1
Forwarded from Библиотека задач по C++ | тесты, код, задания
🏆 Задача на выходные: string_view vs string в API
Перед тобой два варианта API логгера. Выбери лучший и обоснуй. Нет единственно верного ответа — важна аргументация.
✏️ Напиши в комментариях: какой метод в каком варианте правильный, а какой — нет. Предложи «идеальный»
📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#константная_правильность
Перед тобой два варианта API логгера. Выбери лучший и обоснуй. Нет единственно верного ответа — важна аргументация.
#include <string>
#include <string_view>
// Вариант А
class LoggerA {
public:
void log(const std::string& msg);
void setPrefix(const std::string& prefix);
std::string getLastMessage() const;
};
// Вариант Б
class LoggerB {
public:
void log(std::string_view msg);
void setPrefix(std::string_view prefix);
std::string_view getLastMessage() const;
};
// Контекст использования:
// 1. log() вызывается тысячи раз в секунду
// 2. setPrefix() — один раз при старте
// 3. getLastMessage() — для диагностики
// 4. Логгер хранит последнее сообщение внутри
LoggerC.📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#константная_правильность
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🥱1
По умолчанию, когда вы нажимаете
F11 (Step Into) в Visual Studio, отладчик проваливается в каждую функцию — включая стандартную библиотеку, runtime и сторонний код?Функция
Just My Code решает эту проблему. При включении отладчик автоматически перешагивает через код, который не принадлежит вашему проекту — будь то STL, CRT или любые внешние библиотеки.Tools → Options → Debugging → General → Enable Just My Code
#include <vector>
#include <algorithm>
#include <iostream>
int doubleValue(int x) {
return x * 2; // ← ВАШ код
}
int main() {
std::vector<int> v = {3, 1, 4, 1, 5};
// F11 здесь без JMC → провалится в std::sort
std::sort(v.begin(), v.end());
// F11 здесь без JMC → провалится в std::transform
std::transform(v.begin(), v.end(), v.begin(), doubleValue);
return 0;
}
Без JMC: F11 на
std::sort уводит вас в дебри introsort внутри STL.С JMC: отладчик перепрыгивает sort и останавливается на следующей вашей строке.
📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍1
Forwarded from Библиотека задач по C++ | тесты, код, задания
Этот код содержит баг. Необходимо найди его:
#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> vec = { 5, 3, 1, 4, 2 };
auto sorted_view = vec
| std::views::transform([](int x) { return x; });
std::ranges::sort(sorted_view);
for (auto v : sorted_view) {
std::cout << v << " ";
}
}
Подсказка:
Отсортируется ли
vec? Если нет — какая ошибка компиляции и почему?📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#междусобойчик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2😁2
🧹 Сколько мусора в ваших #include?
В больших C++-проектах заголовки превращаются в паутину неявных зависимостей. Один рефакторинг — и всё сыплется, потому что кто-то полагался на транзитивный include.
• IWYU — инструмент на базе Clang, который анализирует, какие заголовки реально используются в каждом .cc/.cpp-файле, а какие тянутся впустую
• Удаление лишних include сокращает время компиляции
• Инструмент умеет подставлять forward declarations вместо полных include, что дополнительно режет зависимости
• Актуальная версия 0.26 совместима с Clang 22. Проект жив, обновляется под каждый мажорный релиз LLVM
👉 Github
✏️ Используете
📍 Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#буст
В больших C++-проектах заголовки превращаются в паутину неявных зависимостей. Один рефакторинг — и всё сыплется, потому что кто-то полагался на транзитивный include.
• IWYU — инструмент на базе Clang, который анализирует, какие заголовки реально используются в каждом .cc/.cpp-файле, а какие тянутся впустую
• Удаление лишних include сокращает время компиляции
• Инструмент умеет подставлять forward declarations вместо полных include, что дополнительно режет зависимости
• Актуальная версия 0.26 совместима с Clang 22. Проект жив, обновляется под каждый мажорный релиз LLVM
👉 Github
✏️ Используете
IWYU на своих проектах или до сих пор чистите include вручную? 👇📍 Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#буст
👾7😁2
🔥 Препроцессор C++ — наследие, от которого не сбежать
Несмотря на все усилия комитета по стандартизации,
Главная проблема — текстовая подстановка. Макрос не проверяет типы, не уважает пространства имён и может сломать код в самом неожиданном месте. Классический пример:
Современный C++ предлагает альтернативы почти для каждого сценария:
✏️ А в вашем проекте много макросов, или удалось от них почти избавиться?
📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#междусобойчик
Несмотря на все усилия комитета по стандартизации,
#include и #define по-прежнему живут в каждом проекте. Препроцессор — это, по сути, отдельный язык, работающий до компиляции, и он ничего не знает о типах, областях видимости и прочих правилах C++.Главная проблема — текстовая подстановка. Макрос не проверяет типы, не уважает пространства имён и может сломать код в самом неожиданном месте. Классический пример:
#define max(a,b) ((a)>(b)?(a):(b)) — попробуйте передать туда i++, и получите двойной инкремент.Современный C++ предлагает альтернативы почти для каждого сценария:
constexpr, consteval, inline-функции, шаблоны. Но полностью убить препроцессор пока не удалось.📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#междусобойчик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9😁3
Forwarded from Библиотека собеса по C++ | вопросы с собеседований
Проведи ревью кода и найди проблему (если она есть😉).
#include <mutex>
#include <thread>
#include <vector>
#include <iostream>
std::mutex mtx;
std::vector<int> data;
void producer() {
for (int i = 0; i < 100; ++i) {
std::lock_guard<std::mutex> lock(mtx);
data.push_back(i);
}
}
void consumer() {
while (true) {
std::lock_guard<std::mutex> lock(mtx);
if (data.empty()) {
// Ждём данные...
std::this_thread::sleep_for(
std::chrono::milliseconds(10));
continue;
}
std::cout << data.back() << "\n";
data.pop_back();
}
}
Вопрос: что не так с
consumer()? Почему lock_guard здесь — плохой выбор и как это исправить?📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#междусобойчик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2😁2🥱2
Если в новом коде ты по привычке тянешься к
std::function — в C++26 для большинства случаев есть вариант лучше.std::function живёт с C++11, но у него два врождённых дефекта. Первый — он раздувает бинарь. Второй, более коварный — дефект const-корректности: operator() помечен const, но при этом спокойно вызывает не-const operator() хранимого объекта. Починить нельзя — сломается ABI.std::copyable_function — то, чем std::function должен был быть с самого начала: копируемый, const-корректный, поддерживает весь набор квалификаторов (const, noexcept, &/&&).#include <functional>
// const здесь означает const на самом деле
std::copyable_function<int() const> f = [x = 42] { return x; };
int y = f(); // 42
// std::copyable_function<int() const> bad = [x=42]() mutable {...}; // ❌ mutable не пройдёт
std::copyable_function<void()> g; // пустой
// g(); // ⚠️ UB, а НЕ bad_function_call
copyable_function — это UB, а не исключение. Сделано осознанно, ради консистентности с остальной библиотекой.• у
copyable_function нет target() / target_type() — никакой RTTI-интроспекции• пустой вызов → UB вместо
bad_function_call: ловившие исключение сломаются молча• для стабильного ABI существующих интерфейсов
std::function по-прежнему уместен📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#под_капотом
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Прежде чем хвалить C++23, разберёмся с тем, что встречается в каждом проекте.
errno — индикатор ошибки из мира C, и его всё ещё использует унаследованная C-часть стандартной библиотеки (<cmath>, семейство strto*, часть C-I/O).errno не сбрасывается при успехе. Проверять его «после» наугад бессмысленно — нужно обнулить до вызова.#include <cerrno>
#include <cstdlib>
errno = 0; // 1. сбросить
char* end = nullptr;
long v = std::strtol(str, &end, 10);
if (errno == ERANGE) return overflow(); // 2. проверить переполнение
if (end == str) return empty(); // 3. ничего не распарсилось
if (*end != '\0') return trailing(); // 4. мусор в хвосте: "123abc"
• забыли
errno = 0 перед вызовом• смотрят только на результат, игнорируя
ERANGE• думают, что
errno общий на все потоки (с C++11 он thread-local)std::strerror(errno).errno неизбежен, но в своём коде его стоит сразу заворачивать в std::error_code.📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#константная_правильность
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Коллега написал таймаут для сетевого запроса и клянётся, что «иногда он срабатывает мгновенно, а иногда висит вечно». Особенно после перевода часов. Найдёшь причину?
#include <chrono>
using namespace std::chrono;
bool wait_for_response(Connection& conn, int timeout_ms) {
auto deadline = system_clock::now() + milliseconds(timeout_ms);
while (system_clock::now() < deadline) {
if (conn.has_data()) return true;
std::this_thread::sleep_for(milliseconds(10));
}
return false;
}
Задача: объясни, почему таймаут ведёт себя непредсказуемо, и перепиши функцию так, чтобы она работала корректно всегда.
📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#междусобойчик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3😁1
C++23 значительно расширил библиотеку Ranges. Рассмотрим важнейшие добавления.
Раньше преобразование view в контейнер было неудобным:
// C++20: нужно было делать так
std::vector<int> v = {1, 2, 3, 4, 5};
auto view = v | views::filter([](int x) { return x > 2; });
std::vector<int> result(view.begin(), view.end()); // громоздко!
C++23 добавляет
std::ranges::to:// C++23: красиво и лаконично
auto result = v
| views::filter([](int x) { return x > 2; })
| std::ranges::to<std::vector>();
// result = {3, 4, 5}
// Можно указать тип элементов явно
auto strs = views::iota(1, 6)
| views::transform([](int x){ return std::to_string(x); })
| std::ranges::to<std::vector<std::string>>();
// strs = {"1", "2", "3", "4", "5"}
// Работает и с другими контейнерами
auto s = some_range | std::ranges::to<std::set>();
auto m = pairs_range | std::ranges::to<std::map>();
views::zip_transform — zip + transform в одномstd::vector<int> a = {1, 2, 3};
std::vector<int> b = {10, 20, 30};
// Попарная сумма
auto sums = views::zip_transform(std::plus{}, a, b);
// 11, 22, 33views::adjacent — соседние N-киstd::vector<int> v = {1, 2, 3, 4, 5};
// Пары соседних элементов
for (auto [a, b] : v | views::adjacent<2>) {
std::cout << "(" << a << "," << b << ") "; // (1,2) (2,3) (3,4) (4,5)
}
// Тройки
for (auto [a, b, c] : v | views::adjacent<3>) {
std::cout << a+b+c << " "; // 6 9 12
}views::adjacent_transform — скользящая функцияstd::vector<int> v = {1, 2, 3, 4, 5};
// Скользящий максимум из двух соседних элементов
auto sliding_max = v | views::adjacent_transform<2>(
[](int a, int b) { return std::max(a, b); }
);
// 2, 3, 4, 5views::slide — скользящее окноstd::vector<int> v = {1, 2, 3, 4, 5};
// Скользящее окно размером 3
for (auto window : v | views::slide(3)) {
for (int x : window) std::cout << x << " ";
std::cout << "| ";
}
// 1 2 3 | 2 3 4 | 3 4 5 |views::cartesian_product — декартово произведениеstd::vector<int> xs = {1, 2};
std::vector<char> ys = {'a', 'b', 'c'};
for (auto [x, y] : views::cartesian_product(xs, ys)) {
std::cout << "(" << x << "," << y << ") ";
}
// (1,a) (1,b) (1,c) (2,a) (2,b) (2,c)C++23 добавляет
std::generator<T> — корутину, которая является диапазоном:#include <generator> // C++23
std::generator<int> fibonacci() {
int a = 0, b = 1;
while (true) {
co_yield a;
auto next = a + b;
a = b;
b = next;
}
}
// Использование как обычного диапазона!
for (int f : fibonacci() | views::take(10)) {
std::cout << f << " "; // 0 1 1 2 3 5 8 13 21 34
}
// Можно комбинировать с другими адаптерами
auto big_fibs = fibonacci()
| views::filter([](int x) { return x > 100; })
| views::take(5);
📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#константная_правильность
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3