en
Feedback
C/C++ | Вопросы собесов

C/C++ | Вопросы собесов

Open in Telegram

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv

Show more
4 180
Subscribers
-324 hours
-27 days
-1230 days
Posts Archive
🤔 Какой имеется побочный эффект при работе с кодом в хидере? При работе с кодом в хидерах возможны проблемы, связанные с повторным включением файлов (multiple inclusion), что может вызвать ошибки компиляции. Это решается использованием включающих защит (#pragma once или #ifndef). Также код в хидере увеличивает время компиляции, так как включается в несколько исходных файлов. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний

Квартиры Петербург Колпино Семейная Ипотека 3,5% Жилой комплекс "Квартал Заречье" Санкт-Петербург. Колпино. 4 девятиэтажных ж
Квартиры Петербург Колпино Семейная Ипотека 3,5% Жилой комплекс "Квартал Заречье" Санкт-Петербург. Колпино. 4 девятиэтажных жилых корпуса 8-этажный крытый гараж на 496 парковочных мест В живописном месте у реки Ижора. На первых этажах будут размещены магазины, кофейни, поликлиника и зона коворкинга. Перейти на сайт Изучите все условия кредита (займа) на сайте в соответствующем разделе. Оценивайте свои финансовые возможности и риски. Финансовые услуги оказывает: ПАО «Сбербанк». Проектная декларация на сайте https://наш.дом.рф/. Застройщик: ООО «СЗ «ЗАГОРОДНАЯ, 71». #реклама квартал-заречье.рф О рекламодателе

🤔 Почему со стеком работать быстрее чем с кучей? 🟠Управление памятью Стек: Память в стеке управляется автоматически. Когда вызывается функция, память для её локальных переменных выделяется одним блоком при входе в функцию и освобождается при выходе из неё. Эта операция выполняется за постоянное время (O(1)). Куча: Память в куче управляется вручную (программистом) или через автоматическое управление памятью (например, сборщик мусора). Выделение и освобождение памяти в куче требуют поиска подходящего блока памяти, что может занимать больше времени (O(log n) или даже O(n)). 🟠Локальность данных Стек: Данные в стеке расположены компактно и последовательно. Это означает, что доступ к данным будет быстрее из-за лучшего использования кэш-памяти процессора. Куча: Данные в куче могут быть фрагментированы, что приводит к меньшей эффективности кэширования и увеличению времени доступа. 🟠Предсказуемость Стек: Память в стеке выделяется и освобождается в строго определённом порядке (LIFO - Last In, First Out). Это делает операции со стеком предсказуемыми и упрощает управление памятью. Куча: Память в куче может выделяться и освобождаться в произвольном порядке, что приводит к фрагментации и усложняет управление памятью. 🟠Минимизация накладных расходов Стек: Операции выделения и освобождения памяти на стеке имеют минимальные накладные расходы, так как это просто смещение указателя стека. Куча: Операции выделения и освобождения памяти в куче требуют более сложных алгоритмов и могут включать в себя дополнительные накладные расходы, такие как управление списками свободных блоков и слияние фрагментов.
#include <iostream>

void stackFunction() {
    int stackArray[1000]; // Массив на стеке
    // Работа с массивом
}

void heapFunction() {
    int* heapArray = new int[1000]; // Массив в куче
    // Работа с массивом
    delete[] heapArray; // Освобождение памяти
}

int main() {
    stackFunction(); // Быстрая работа со стеком
    heapFunction();  // Медленная работа с кучей
    return 0;
}
Ставь 👍 и забирай 📚 Базу знаний

Аренда VPS/VDS-сервера. Виртуальные выделенные серверы в дата-центрах уровня Tier III — 7 готовых конфигураций от 200 ₽/мес.
Аренда VPS/VDS-сервера. Виртуальные выделенные серверы в дата-центрах уровня Tier III — 7 готовых конфигураций от 200 ₽/мес. Преимущества аренды: - Выделенные ресурсы без переплаты; - KVM-виртуализация; - Быстрые NVMe SSD; - Бесплатная защита от DDoS; - Управление через панель, API и Terraform; - Техподдержка 24/7. Запустите сервер за несколько минут! Попробовать #реклама 16+ selectel.ru О рекламодателе

Пожизненный PRO доступ на easyoffer — по цене одного года! До 2 сентября вы можете купить PRO навсегда. Покупаешь один раз — пользуешься всю жизнь. – База вопросов и задач из собеседований – Примеры видео-ответов на вопросы – Записи реальных собеседований – Тренажеры "Проработка вопросов" и "Реальное собеседование" – Аналитика требований из вакансий – Автоотклики на вакансии – Агрегатор вакансий (скоро) 👉 Купить PRO со скидкой 70%: https://easyoffer.ru/pro

🤔 Сколько занимает места объект пустого класса? Объект пустого класса не может иметь нулевой размер из-за требований стандарта. Поэтому компилятор добавляет "фиктивный байт" (dummy byte), чтобы каждый объект имел уникальный адрес. Простой пример
#include <iostream>

class Empty {};

int main() {
    std::cout << "Размер пустого класса: " << sizeof(Empty) << " байт\n";
    return 0;
}
Вывод (на большинстве компиляторов):
Размер пустого класса: 1 байт
Что если создать массив пустых объектов?
#include <iostream>

class Empty {};

int main() {
    Empty arr[10]; // Создаем массив из 10 объектов

    std::cout << "Размер массива из 10 пустых объектов: " << sizeof(arr) << " байт\n";
    return 0;
}
Вывод
Размер массива из 10 пустых объектов: 10 байт
🟠Унаследованный пустой класс (Empty Base Optimization - EBO) Если пустой класс используется в наследовании, компилятор может убрать его размер (оптимизация Empty Base Optimization, EBO).
#include <iostream>

class Empty {};

class Derived : public Empty {
    int value; // 4 байта (обычно)
};

int main() {
    std::cout << "Размер пустого класса: " << sizeof(Empty) << " байт\n";
    std::cout << "Размер наследника: " << sizeof(Derived) << " байт\n";
    return 0;
}
Вывод
Размер пустого класса: 1 байт
Размер наследника: 4 байта (а не 5!)
Ставь 👍 и забирай 📚 Базу знаний

Решайте задачи и готовьтесь к техсекции на стажировку А ты сможешь решить алгоритмическую задачу за час и без подсказок? Янде
Решайте задачи и готовьтесь к техсекции на стажировку А ты сможешь решить алгоритмическую задачу за час и без подсказок? Яндекс проводит бесплатные тренировки по алгоритмам для тех, кто хочет систематизировать знания, прокачать решение задач и подготовиться к техническому собеседованию. -Короткие видеоуроки -Практические задачи -Регулярные соревнования -Решение задач на время -Рейтинг и награды -Возможность получить сертификат Мы тренируем не только знание алгоритмов, но и умение применять их тогда, когда рядом нет подсказок. Проверь свои алгоритмические навыки и прокачай слабые места. Регистрируйся на бесплатные тренировки! Записаться онлайн #реклама 16+ yandex.ru О рекламодателе

🤔 Как устроена хеш таблица в unordered_map? std::unordered_map в C++ реализован на основе хеш-таблицы. Это структура данных, обеспечивающая O(1) доступ к элементам в среднем случае. 🚩Основные компоненты хеш-таблицы 🟠Массив "бакетов" (buckets) Хеш-таблица состоит из массива бакетов, где каждый бакет содержит список элементов с одинаковым хеш-кодом. 🟠Функция хеширования (`std::hash<T>`) Для определения, в какой бакет попадёт ключ, используется функция хеширования (std::hash<T>). 🟠Проверка коллизий Если два разных ключа попадают в один бакет (коллизия), элементы сохраняются в связанном списке (чаще всего). 🟠Рехеширование При переполнении таблицы (load_factor > порогового значения) количество бакетов увеличивается, и все элементы перераспределяются. 🚩Как работает поиск и вставка в `unordered_map` Хеш-функция вычисляет хеш-код ключа
   std::hash<int> hash_fn;
   size_t hash_value = hash_fn(42); // Например, 23145123
Определяется индекс бакета
   size_t bucket_index = hash_value % bucket_count;
🚩Разрешение коллизий Когда два ключа попадают в один бакет, возникают коллизии. std::unordered_map использует метод цепочек (separate chaining): В каждом бакете хранится связанный список (или другой контейнер). Если несколько элементов имеют одинаковый хеш, они добавляются в этот список.
#include <iostream>
#include <unordered_map>

int main() {
    std::unordered_map<int, std::string> myMap;

    myMap[1] = "One";  // Хеш-функция определит бакет
    myMap[2] = "Two";  // Если попадает в тот же бакет, создаётся список

    for (const auto& [key, value] : myMap) {
        std::cout << "Key: " << key << ", Value: " << value << '\n';
    }

    return 0;
}
🚩Рехеширование (увеличение количества бакетов) Когда таблица заполняется, выполняется rehash (увеличение массива бакетов в 2 раза). Load factor (load_factor()) показывает, насколько заполнена таблица:
std::unordered_map<int, std::string> myMap;
std::cout << "Load factor: " << myMap.load_factor() << '\n';
Ставь 👍 и забирай 📚 Базу знаний

Регистрируйтесь на Yandex Scale 2026 Главная конференция Yandex Cloud. Узнайте о сервисах, которые меняют ваш бизнес. 4 офлай
+5
Регистрируйтесь на Yandex Scale 2026 Главная конференция Yandex Cloud. Узнайте о сервисах, которые меняют ваш бизнес. 4 офлайн-трека (AI, Infra + DevTools, Data, Security), онлайн-трек Deep Tech, воркшопы по ИИ и интерактивы. Подробнее о программе читайте в карточках🗒 📅24 сентября 🚗Москва + 💻онлайн Участие бесплатное! Зарегистрироваться #реклама 16+ scale.yandex.cloud О рекламодателе

🤔 Что знаешь про гарантии безопасности исключений? Гарантии безопасности исключений (Exception Safety Guarantees) — это концепция, связанная с корректным поведением программы при возникновении исключений. Она определяет, насколько безопасно может завершиться выполнение функции или блока кода в случае выбрасывания исключения. 🚩Никаких гарантий (No Guarantee) Этот уровень означает, что при возникновении исключения состояние программы может быть непредсказуемым. Объекты могут остаться в недопустимом состоянии, и поведение программы после выброса исключения неопределено.
void unsafeFunction(std::vector<int>& vec, int value) {
    vec.push_back(value); // Если здесь выбросится исключение, состояние vec не определено
    // ...
}
🚩Базовая гарантия (Basic Guarantee) Этот уровень гарантирует, что не произойдёт утечек ресурсов или нарушений инвариантов объектов. После выброса исключения все объекты остаются в допустимом состоянии, однако состояние программы может быть частично изменено.
void safeFunction(std::vector<int>& vec, int value) {
    try {
        vec.push_back(value); // Если исключение, состояние vec остаётся корректным
    } catch (...) {
        // Обработка исключения
        std::cerr << "Ошибка при добавлении элемента!" << std::endl;
    }
}
🚩Сильная гарантия (Strong Guarantee) Этот уровень гарантирует, что в случае возникновения исключения программа останется в исходном состоянии, как будто вызов функции никогда не происходил. Состояние откатывается до того, что было до вызова функции.
void addValue(std::vector<int>& vec, int value) {
    std::vector<int> temp = vec; // Создаём копию
    temp.push_back(value);       // Работаем с копией
    vec = temp;                  // Замена содержимого
}
🚩Гарантия отсутствия исключений (No-Throw Guarantee) Этот уровень гарантирует, что функция никогда не выбрасывает исключений. Обычно применяется к ключевым операциям (например, деструкторам, перемещениям).
void safeSwap(std::vector<int>& a, std::vector<int>& b) noexcept {
    a.swap(b); // std::vector::swap гарантирует отсутствие исключений
}
🚩Как достигаются гарантии безопасности исключений? 🟠RAII (Resource Acquisition Is Initialization) Использование классов, где ресурсы освобождаются в деструкторах. Например, std::unique_ptr или std::lock_guard. 🟠Копирование перед изменением Применение принципа работы с временными копиями (как в примере сильной гарантии). 🟠Использование стандартных контейнеров Библиотека STL предоставляет базовую гарантию безопасности исключений для большинства операций. Ставь 👍 и забирай 📚 Базу знаний

🤔 Когда нужно объявлять деструктор виртуальным? Виртуальный деструктор нужен всегда, когда класс предполагается использовать в качестве базового и поддерживает полиморфизм (наследование и динамическое связывание). 🚩Зачем нужен виртуальный деструктор? Если у базового класса деструктор не виртуальный, а удаление происходит через указатель на базовый класс, деструктор производного класса не вызовется! Это приведёт к утечке памяти или некорректному освобождению ресурсов. Пример проблемы без виртуального деструктора
#include <iostream>

class Base {
public:
    ~Base() { std::cout << "Деструктор Base\n"; } // НЕ виртуальный!
};

class Derived : public Base {
public:
    ~Derived() { std::cout << "Деструктор Derived\n"; }
};

int main() {
    Base* obj = new Derived();
    delete obj; // Проблема! Деструктор Derived НЕ вызывается!
}
Вывод
Деструктор Base
🚩Решение: сделать деструктор виртуальным Если объявить деструктор базового класса виртуальным (virtual), то при удалении через указатель на базовый класс будет вызван полный цепной деструктор. Используем virtual
class Base {
public:
    virtual ~Base() { std::cout << "Деструктор Base\n"; } // Виртуальный!
};

class Derived : public Base {
public:
    ~Derived() { std::cout << "Деструктор Derived\n"; }
};

int main() {
    Base* obj = new Derived();
    delete obj; // Теперь вызываются оба деструктора
}
Вывод
Деструктор Derived
Деструктор Base
🚩Когда не нужно делать деструктор виртуальным? Когда класс не предназначен для наследования Например, std::vector, std::string, std::unique_ptr – у них нет виртуального деструктора, так как они не предполагают полиморфное использование Когда удаление всегда происходит по ссылке/указателю на сам класс, а не на базовый
   Derived* obj = new Derived();
   delete obj; // В любом случае вызовет правильный деструктор
Если класс "заморожен" (final)
   class FinalClass final {
   public:
       ~FinalClass() { std::cout << "Деструктор\n"; }
   };
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое deque? Deque (double-ended queue, двусторонняя очередь) — это последовательный контейнер в C++, который позволяет добавлять и удалять элементы как с начала, так и с конца очереди с постоянной временной сложностью O(1). Контейнер deque является частью стандартной библиотеки шаблонов (STL) и объявляется в заголовочном файле <deque>. 🚩Основные характеристики: 🟠Быстрый доступ к элементам: deque обеспечивает доступ к элементам по индексу с амортизированной временной сложностью O(1). 🟠Двусторонняя очередь: Позволяет эффективно добавлять и удалять элементы как с начала, так и с конца очереди. 🟠Динамический размер: deque автоматически изменяет свой размер по мере добавления или удаления элементов, подобно vector. 🟠Не требует смежного хранения: В отличие от vector, элементы deque могут быть размещены в различных сегментах памяти, что делает его более гибким для частых операций вставки и удаления. 🚩Основные операции: 🟠Добавление элементов: push_back(), push_front() 🟠Удаление элементов: pop_back(), pop_front() 🟠Доступ к элементам: operator[], at(), front(), back() 🟠Размер и емкость: size(), empty(), resize() 🟠Итераторы: Поддержка итераторов для прохода по элементам
#include <iostream>
#include <deque>

int main() {
    std::deque<int> dq;

    // Добавление элементов в конец
    dq.push_back(1);
    dq.push_back(2);
    dq.push_back(3);

    // Добавление элементов в начало
    dq.push_front(0);

    std::cout << "Deque elements: ";
    for (int elem : dq) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    // Удаление элемента с конца
    dq.pop_back();

    // Удаление элемента с начала
    dq.pop_front();

    std::cout << "Deque elements after pop operations: ";
    for (int elem : dq) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое наследование? Наследование — это механизм ООП, позволяющий одному классу (наследнику) унаследовать свойства и методы другого класса (родителя) для повторного использования и расширения. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний

🤔 Что такое placement new? placement new – это специальная форма оператора new, которая размещает объект в уже выделенной памяти вместо того, чтобы выделять её заново. placement new НЕ выделяет память (мы сами передаём адрес). Просто вызывает конструктор в указанном месте.
void* ptr = malloc(sizeof(int));   // Выделяем память вручную
int* num = new(ptr) int(42);       // Размещаем объект в этой памяти
Синтаксис placement new
new (адрес) Type(аргументы конструктора);
адрес – указатель на уже выделенную память. Type(аргументы конструктора) – объект создаётся в этом месте.
#include <iostream>

int main() {
    char buffer[sizeof(int)];  // Буфер памяти (размер как у int)

    int* p = new (buffer) int(123);  // Размещаем int в этом буфере

    std::cout << "Значение: " << *p << std::endl;  // 123
}
🚩Когда используется `placement new`? 🟠Оптимизация выделения памяти Например, если у нас часто создаются и удаляются объекты, но память уже есть. Не нужно каждый раз вызывать new и delete. 🟠Размещение объектов в особых областях памяти Например, на стеке (char buffer[100]), в shared memory, или в выделенной заранее области (malloc). 🟠Создание объекта в заранее выделенном массиве Стандартный std::vector использует placement new внутри себя! 🟠Кастомные аллокаторы (`std::allocator`) Например, в играх и в embedded-разработке, где управление памятью критично. 🚩`placement new` и классы Если объект – это класс, placement new вызывает его конструктор в выделенной памяти.
#include <iostream>
#include <cstdlib>  // Для malloc/free

class MyClass {
public:
    int x;
    MyClass(int val) : x(val) { std::cout << "Конструктор!\n"; }
    ~MyClass() { std::cout << "Деструктор!\n"; }
};

int main() {
    void* buffer = malloc(sizeof(MyClass));  // Выделяем сырую память
    MyClass* obj = new (buffer) MyClass(42); // Размещаем объект

    std::cout << "Значение: " << obj->x << std::endl;

    obj->~MyClass();  // Ручной вызов деструктора!
    free(buffer);     // Освобождаем память
}
Вывод
Конструктор!
Значение: 42
Деструктор!
🚩Ошибки при `placement new` Забыл вызвать деструктор
MyClass* obj = new (buffer) MyClass(10);
// delete obj; // НЕЛЬЗЯ! Обычный `delete` не работает
free(buffer); // Память утекла! Деструктор не вызвался
Нужно вызвать вручную
obj->~MyClass();
free(buffer);
placement new в одном буфере несколько раз (без очистки)*
void* buffer = malloc(sizeof(MyClass));
MyClass* obj1 = new (buffer) MyClass(1);
MyClass* obj2 = new (buffer) MyClass(2); // Перезапишет obj1!
Нужно сначала вызвать деструктор
obj1->~MyClass();
MyClass* obj2 = new (buffer) MyClass(2);
Освободил память перед вызовом деструктора
free(buffer);  // Память освободили
obj->~MyClass(); // ОШИБКА! Память уже не существует
Правильный порядок
obj->~MyClass();
free(buffer);
Ставь 👍 и забирай 📚 Базу знаний

Не знак свыше, а точный таргетинг Теперь всем, кто продвигается через CTV в Яндекс Директе, стало проще находить свою аудитор
Не знак свыше, а точный таргетинг Теперь всем, кто продвигается через CTV в Яндекс Директе, стало проще находить свою аудиторию. Таргетингов стало в 5 раз больше. Вот что нового: — Таргетинг по интересам. Например, можно выбрать не всех, кто интересуется спортом, а только любителей фитнеса или тенниса. — Таргетинг по привычкам. Находите аудиторию по поведению в онлайне и офлайне — например, тех, кто регулярно посещает торговые центры или часто покупает товары в интернете. — Более гибкие настройки. Можно сочетать интересы и социально-демографические характеристики с жанрами и тематиками контента. 👌 Используйте новые возможности, чтобы сделать рекламу на Connected TV еще эффективнее Узнать больше #реклама yandex.ru О рекламодателе

🤔 Какие виды конструкторов могут быть у класса? 🟠Конструктор по умолчанию (Default Constructor) Без параметров, создается автоматически компилятором, если не задан.
   class MyClass {
   public:
       MyClass() {}
   };
🟠Параметризованный конструктор (Parameterized Constructor) Принимает параметры для инициализации объекта.
   class MyClass {
   private:
       int x;
   public:
       MyClass(int value) : x(value) {}
   };
🟠Конструктор копирования (Copy Constructor) Создает копию существующего объекта.
   class MyClass {
   private:
       int x;
   public:
       MyClass(const MyClass &other) : x(other.x) {}
   };
🟠Конструктор перемещения (Move Constructor) Перемещает ресурсы из временного объекта.
   class MyClass {
   private:
       int* data;
   public:
       MyClass(MyClass&& other) noexcept : data(other.data) {
           other.data = nullptr;
       }
   };
🟠Делегирующий конструктор (Delegating Constructor) Вызывает другой конструктор того же класса.
   class MyClass {
   private:
       int x, y;
   public:
       MyClass(int value) : MyClass(value, 0) {}
       MyClass(int value1, int value2) : x(value1), y(value2) {}
   };
🟠Явный конструктор (Explicit Constructor) Помечен explicit для предотвращения неявных преобразований.
   class MyClass {
   public:
       explicit MyClass(int value) {}
   };
Ставь 👍 и забирай 📚 Базу знаний

Gurufy 📚 Gurufy — ИИ-сервис, который собирает персональный курс под вашу задачу: план из глав, статьи с иллюстрациями и инте
Gurufy 📚 Gurufy — ИИ-сервис, который собирает персональный курс под вашу задачу: план из глав, статьи с иллюстрациями и интерактивными виджетами, задания и ИИ-ассистент прямо в главе. ✨ Простой вопрос быстрее задать ChatGPT. Но когда на тему нужен день и больше, одним чатом её не закрыть: нет плана, нет визуализаций, нет заданий — всё тонет в одной переписке. 🎓 Готовый курс — десятки тысяч рублей против 500–1000 ₽. ⚡ Попробуйте сами. Старт бесплатный. Узнать больше #реклама 16+ gurufy.ru О рекламодателе

🤔 В каких STL контейнерах внутри находится хеш таблица? 🚩В стандартной библиотеке шаблонов (STL) C++ хеш-таблица используется для реализации следующих контейнеров 🟠std::unordered_map Ассоциативный контейнер, который хранит пары ключ-значение, с уникальными ключами. Обеспечивает амортизированное среднее время доступа, вставки и удаления за O(1). 🟠std::unordered_multimap Ассоциативный контейнер, который хранит пары ключ-значение, где ключи могут повторяться. Обеспечивает амортизированное среднее время для основных операций за O(1), несмотря на дублирование ключей. 🟠std::unordered_set Ассоциативный контейнер, который хранит уникальные элементы, неупорядоченные. Обеспечивает амортизированное среднее время для основных операций за O(1). 🟠std::unordered_multiset Ассоциативный контейнер, который хранит элементы, где значения могут повторяться, неупорядоченные. Обеспечивает амортизированное среднее время для основных операций за O(1), несмотря на дублирование элементов. Ставь 👍 и забирай 📚 Базу знаний

Дачная дача в Т-Банк Шопе Футболки с огурцами, тыквами, капустой и другие крутые штуки, да еще и с финансовыми пожеланиями. Н
Дачная дача в Т-Банк Шопе Футболки с огурцами, тыквами, капустой и другие крутые штуки, да еще и с финансовыми пожеланиями. Надо брать. Посмотреть каталог #реклама tbank.ru О рекламодателе

🤔 Как работает range based? Range-based for loop – это упрощённый цикл for, который позволяет перебирать элементы контейнера (std::vector, std::array, std::map, std::set и т. д.) без индексов и итераторов.
for (auto element : container) {
    // Действие с element
}
🚩Как это работает внутри? Простой пример с std::vector
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    for (int x : v) { // Перебираем все элементы вектора
        std::cout << x << " ";
    }
}
Вывод
1 2 3 4 5
Как работает этот цикл? Компилятор превращает его в обычный for с итератором:
for (auto it = v.begin(); it != v.end(); ++it) {
    int x = *it; // Копируем элемент
    std::cout << x << " ";
}
🚩Передача по ссылке (`&`) и по значению (`=`) Передача по значению (=) – создаёт копию элемента
for (int x : v) { // x - копия элемента
    x = 100; // НЕ изменит вектор!
}
Передача по ссылке (&) – изменяет оригинал
for (int& x : v) { // x - ссылка на элемент
    x *= 2; // Изменит оригинальный вектор!
}
🚩Работает со всеми контейнерами STL С std::map
std::map<int, std::string> m = {{1, "one"}, {2, "two"}};
for (const auto& [key, value] : m) { // structured binding (C++17)
    std::cout << key << " -> " << value << "\n";
}
С std::set
std::set<int> s = {1, 2, 3, 4};
for (int x : s) { std::cout << x << " "; }
🚩Работает с `std::initializer_list`
for (int x : {10, 20, 30}) {
    std::cout << x << " ";
}
Вывод
10 20 30
🚩Как работает range-based for с обычными массивами?
int arr[] = {1, 2, 3};
for (int x : arr) { std::cout << x << " "; }
Работает так же, как и с `std::vector`! Работает с пользовательскими классами (если есть begin() и end())
class MyContainer {
    int data[3] = {10, 20, 30};
public:
    int* begin() { return data; }
    int* end() { return data + 3; }
};

int main() {
    MyContainer c;
    for (int x : c) { std::cout << x << " "; }
}
Ставь 👍 и забирай 📚 Базу знаний