PrepBro
Профессии
PrepBro
Профессия:

Подготовка

  • Вопросы652
  • Задачи13

Аналитика

  • hh статистика
  • Анализ резюме

Практика

  • Тестовое собеседование
  • Mock-собеседование
  • Менторы

Поддержка / отзывы

Telegram админа
Профессия:

Подготовка

  • Вопросы652
  • Задачи13

Аналитика

  • hh статистика
  • Анализ резюме

Практика

  • Тестовое собеседование
  • Mock-собеседование
  • Менторы

Поддержка / отзывы

Telegram админа
Все 24 профессии
Android DeveloperData AnalystSystem Analyst1С DeveloperiOS DeveloperBusiness AnalystJava DeveloperData ScientistQA EngineerQA AutomationPHP BackendC/C++ BackendDevOps EngineerIT Project ManagerFrontend DeveloperNode.js BackendUnity DeveloperC# BackendProduct AnalystFlutter DeveloperPython DeveloperIT Product ManagerGo DeveloperData Engineer

© 2026 PrepBro. Все права защищены.

Telegram-бот

Задачи по C/C++ Backend

Потокобезопасный singleton
2.0 Middle🔥 25💬 1

Решение: Потокобезопасный Singleton на C++11

Лучший подход: Magic Statics (Scott Meyers)

Начиная с C++11 стандарт гарантирует потокобезопасную инициализацию локальных статических переменных. Это самое элегантное и надёжное решение:

template <typename T>
class Singleton {
public:
    static T& getInstance() {
        static T instance;
        return instance;
    }
    
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(Singleton&&) = delete;
    
protected:
    Singleton() = default;
    ~Singleton() = default;
};

Использование

class Logger : public Singleton<Logger> {
public:
    void log(const std::string& message) {
        std::cout << "[LOG] " << message << std::endl;
    }
    
protected:
    friend class Singleton<Logger>;
    Logger() { std::cout << "Logger initialized" << std::endl; }
};
Читать полностью ->
Пул потоков (Thread Pool)
3.0 Senior🔥 23💬 1

Решение: Пул потоков (Thread Pool)

Архитектура

Пул потоков состоит из:

  1. Рабочие потоки — ждут задач в очереди
  2. Очередь задач — thread-safe queue с задачами (std::packaged_task)
  3. Condition Variable — сигнализирует, что задача поступила

Ключевая идея: рабочие потоки циклически ждут задач, выполняют их и кладут результат в future.

Полная реализация

#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <functional>
#include <future>
#include <vector>
#include <memory>
Читать полностью ->
Реализация LRU Cache
1.8 Middle🔥 22💬 1

Решение: Реализация LRU Cache

Описание подхода

Для достижения требуемой O(1) сложности для обеих операций используем комбинацию двусвязного списка (std::list) и хеш-таблицы (std::unordered_map):

  • std::list хранит пары (ключ, значение) в порядке использования. Самый свежий элемент находится в конце, самый старый — в начале
  • std::unordered_map отображает ключ на итератор в списке для O(1) доступа к элементам

Этот подход позволяет:

  • Быстро найти элемент по ключу (O(1) через хеш-таблицу)
  • Быстро переместить элемент в конец списка при обращении (O(1) благодаря двусвязности)
  • Быстро удалить самый старый элемент (O(1) — просто удалить начало списка)

Реализация

#include <unordered_map>
#include <list>
Читать полностью ->
Потокобезопасная очередь
1.8 Middle🔥 21💬 1

Решение: Потокобезопасная очередь

Архитектура

Потокобезопасная очередь (thread-safe queue) комбинирует:

  1. std::queue — базовая очередь с FIFO
  2. std::mutex — защита критических секций
  3. std::condition_variable — сигнализирует потребителям о наличии данных

Ключевая идея: потребители блокируются на condition_variable и просыпаются, когда producer добавляет элемент.

Полная реализация

#include <queue>
#include <mutex>
#include <condition_variable>
#include <memory>
Читать полностью ->
Задача про заправки (Gas Station)
2.3 Middle🔥 19💬 1

Решение: Задача про заправки (Gas Station)

Ключевое наблюдение

Эта задача решается одним проходом благодаря важному свойству:

Если общее количество топлива >= общего расхода, решение всегда существует. Нужно только найти правильную стартовую точку.

Стратегия поиска стартовой точки:

  • Если мы начнём со станции i и в какой-то момент баланс станет отрицательным, то начинать нельзя ни с какой станции от i до текущей точки
  • Попытаемся начать со следующей станции

Полное решение

Читать полностью ->
Поиск дубликатов в массиве с условием
1.3 Junior🔥 19💬 1

Решение: Поиск дубликатов с условием на расстояние

Подход: Скользящее окно (Sliding Window) + Хеш-таблица

Идея состоит в том, что мы поддерживаем окно размера k+1, содержащее только элементы, которые могут образовать пару. Если в этом окне два элемента одинаковы — мы нашли ответ.

Ключевое наблюдение: Если два индекса i и j удовлетворяют условию |i - j| <= k, то в момент обработки индекса j, индекс i находится в окне [j-k, j].

Реализация

#include <vector>
#include <unordered_set>
Читать полностью ->
Реализация умного указателя shared_ptr
1.7 Middle🔥 16💬 1

Решение: Реализация умного указателя shared_ptr

Концепция

shared_ptr использует подсчёт ссылок (reference counting) для автоматического управления памятью:

  • Каждый shared_ptr указывает на блок контрольной информации (control block)
  • Control block содержит: указатель на объект, счётчик ссылок, функцию-deleter
  • При копировании shared_ptr счётчик увеличивается
  • При разрушении счётчик уменьшается, и если он 0 — объект удаляется

Полная реализация

#include <iostream>
#include <utility>
Читать полностью ->
Генератор идентификаторов
2.0 Middle🔥 15💬 1

Решение: Генератор идентификаторов на C++

Анализ системы счисления

Это система с переменным основанием: каждый уровень состоит из пар (буква, цифра):

  • A1-Z9: 26 букв × 9 цифр = 234 комбинации
  • A1-A1 до Z9-Z9: вложенные пары второго уровня

Реализация

Класс хранит счётчик и конвертирует его в ID:

Читать полностью ->
Многопоточный TCP-сервер
2.0 Middle🔥 14💬 1

Решение: Многопоточный TCP-сервер на C++

Архитектура

Сервер состоит из двух основных частей:

  1. accept loop — главный поток слушает входящие подключения
  2. client handler threads — отдельный поток для каждого клиента выполняет echo

Полная реализация

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <atomic>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
Читать полностью ->
Найти проблемы в коде (dynamic_cast)
1.0 Junior🔥 13💬 1

Решение: Анализ проблем с dynamic_cast

Проблема 1: dynamic_cast требует виртуального деструктора

Проблема: Базовый класс не имеет виртуального деструктора:

class Base {
public:
    void print() { ... }  // ❌ деструктор не виртуальный
};

Что произойдёт:

  • Компиляция: Код компилируется, но с undefined behavior при выполнении
  • Выполнение: dynamic_cast может не работать корректно, так как RTTI (Run-Time Type Information) недоступна без виртуального деструктора
  • Утечка памяти: Когда вызовем delete b1 через Base*, разрушится только Base (Derived деструктор не вызовется)

Вывод кода БЕЗ исправлений:

Derived only
Segmentation Fault / Undefined Behavior

Проблема 2: Отсутствие проверки результата dynamic_cast

Проблема: После dynamic_cast не проверяется, вернул ли он nullptr:

void process(Base* ptr) {
    Derived* d = dynamic_cast<Derived*>(ptr);
    d->derivedOnly();  // ❌ если d == nullptr, это UB!
}
Читать полностью ->
Вычисление выражения в обратной польской записи
1.0 Junior🔥 13💬 1

Решение: Вычисление Reverse Polish Notation (RPN)

Принцип работы

Обратная польская нотация (RPN) — это постфиксная запись, где операторы идут ПО СЛЕ операндов. Её главное преимущество — вычисление слева направо без скобок и приоритетов.

Алгоритм:

  1. Проходим по массиву слева направо
  2. Если элемент — число, кладём его в стек
  3. Если элемент — оператор, извлекаем два верхних элемента, выполняем операцию, кладём результат обратно
  4. В конце стека остаётся результат

Реализация

#include <vector>
#include <string>
#include <stack>
#include <cctype>
#include <stdexcept>
Читать полностью ->
Бесконечный цикл с unsigned char
1.0 Junior🔥 11💬 1

Решение: Бесконечный цикл с unsigned char

Анализ проблемы

Исходный код имеет критическую ошибку переполнения типа.

Вычисление выражения

unsigned char half_limit = 150;
for (unsigned char i = 0; i < 2 * half_limit; ++i)

Важно: 2 * half_limit вычисляется как выражение, а не как присваивание!

Шаг 1: Integer promotion

  • half_limit имеет тип unsigned char
  • В выражении 2 * half_limit срабатывает integer promotion
  • unsigned char повышается до int
  • Результат: 2 * 150 = 300 (тип int)

Шаг 2: Сравнение в условии цикла

  • Условие: i < 300
  • i имеет тип unsigned char (диапазон 0-255)
  • 300 имеет тип int
  • Сравнение выполняется с приведением типов

Результат: Цикл выполнит 256 итераций (i от 0 до 255):

  • i = 0, 1, 2, ..., 254, 255 (все значения в диапазоне unsigned char)

Пошаговое объяснение с примерами

Читать полностью ->
Светофор (State Machine)
2.0 Middle🔥 6💬 1

Решение: Светофор (State Machine)

Анализ требований

Необходимо реализовать управление светодиодным светофором с тремя состояниями и чёткими временными переходами. Это классическая задача на паттерн State Machine.

Ключевые требования:

  • RED: 60 сек
  • GREEN: 45 сек
  • YELLOW: 3 сек (переход между RED и GREEN)
  • Экстренное переключение в RED

Реализация паттерна State Machine

#include <iostream>
#include <functional>
#include <chrono>
#include <thread>
#include <mutex>

enum class LightState { RED, YELLOW, GREEN };
Читать полностью ->