#вопросы_с_собеседований Для чего нужен атрибут maybe_unused?
Атрибут [[maybe_unused]]используется для подавления предупреждений компилятора об неиспользуемых объектах.
Компилятор выдает предупреждение, если объект объявлен, но нигде не используется и чтобы избавиться от ложных предупреждений, например, когда объект используется только в отладочной сборке, применяют [[maybe_unused]].
Позволяет задать политику использования на уровне отдельных объектов и улучшает читаемость кода, явно объясняя причину неиспользования.
#вопросы_с_собеседований Для чего нужен атрибут fallthrough?
Атрибут [[fallthrough]]используется для явного указания того, что в конструкции switch нужно пропустить break в конце case и перейти к выполнению следующего case.
По умолчанию в С++17 и новее переход между case без break приводит к ошибке компиляции и чтобы сохранить старое поведение и разрешить переход, нужно добавить [[fallthrough]].
Это улучшает читаемость кода, явно указывая на отсутствие break и помогает избежать случайного отсутствия break, когда разработчик забыл его добавить. [[fallthrough]] также полезен при рефакторинге старого кода с switch в современный стандарт С++.
#вопросы_с_собеседований Может ли inline-функция быть рекурсивной?
Поскольку компилятор просто встраивает код inline-функции в место вызова, не имеет значения, является ли эта функция рекурсивной или нет. Компилятор будет просто копировать один и тот же код функции при каждом рекурсивном вызове.
Таким образом, рекурсивные inline-функции абсолютно допустимы и часто используются, когда нужна рекурсия без накладных расходов на стандартные вызовы функций.
std::generate — это алгоритм из стандартной библиотеки C++, который используется для заполнения диапазона элементов сгенерированными значениями.
Принимает три параметра: начало диапазона, конец диапазона и функцию генерации. Функция генерации должна принимать неявный счетчик и возвращать очередное значение. Для каждого элемента в заданном диапазоне будет вызываться функция генерации, и результат будет записан в этот элемент.
В этом примере std::generate совместно с генератором случайных чисел используется для быстрого заполнения вектора случайными значениями.
std::clamp — это функция из стандартной библиотеки, которая позволяет ограничить значение в заданном диапазоне.
Функция принимает значение, нижнюю и верхнюю границы и возвращает исходное значение, если оно входит в диапазон, или же возвращает ближайшую границу, если значение вне диапазона.
Применяется для:
— Ограничения числовых значений в заданных пределах. — Обработки данных из недостоверных источников. — Защиты от переполнения/обрезания данных. — Нормализации данных в ML и компьютерном зрении. — Реализации игровой логики в движках. — Обработки аудио- и видео- сигналов.
absl::btree — это реализация B-дерева в библиотеке Abseil для C++. Преимущества absl::btree — это хранение данных в отсортированном порядке, быстрый поиск, вставка и удаление за O(logN), поддержка уникальных и неуникальных ключей, реализация set и map.
Применяется в задачах, где нужна высокопроизводительная структура данных с отсортированным доступом, например:
Реализация словарей и сортированных множеств; Для хранения данных в базах данных; В поисковых системах для индексов; В структурах вроде кэша для быстрого доступа; В задачах машинного обучения для хранения данных.
#вопросы_с_собеседований Что такое сложность алгоритма и от чего она зависит?
Сложность алгоритма - это количественная характеристика его эффективности, которая показывает, как зависят затраты ресурсов (времени, памяти) от размера входных данных.
Сложность зависит от:
— Объема операций, которые алгоритм выполняет при обработке данных. — Количества итераций циклов, рекурсивных вызовов. — Зависимости числа операций от размера входных данных. — Операций внутри вложенных циклов и структур.
Чем быстрее растёт сложность функции с ростом входных данных, тем менее эффективен алгоритм.
Функция strrchr(), объявленная в заголовочном файле <cstring>, ищет последнее вхождение указанного символа в строке и возвращает указатель на это вхождение.
Принимает два параметра: указатель на строку и символ для поиска, возвращает указатель на последнее вхождение символа в строке. Если символ не найден, возвращается нулевой указатель.
Полезна, когда нужно найти последнее вхождение разделителя, например точки в URL.
В примере функция strrchr() возвращает указатель на найденный символ, мы вычитаем из этого указателя начало строки, чтобы получить позицию последней точки.
Атрибут nodiscard — это специальный атрибут-маркер, который указывает компилятору предупреждать при игнорировании возвращаемого значения функции или метода.
Он был добавлен в С++17 для улучшения качества кода, указывается перед объявлением функции или метода и информирует компилятор, что возвращаемое значение не должно игнорироваться. Позволяет избежать логических ошибок при игнорировании важных результатов функции.
В этом примере функция getResult() помечена атрибутом [[nodiscard]]. При вызове getResult() без использования возвращаемого значения компилятор выдаст предупреждение об игнорировании результата.
std::size — это функция из стандартной библиотеки C++, которая возвращает размер контейнера или массива.
Она определена в заголовочном файле <iterator>, работает со всеми стандартными контейнерами (vector, deque, list, array и др.) и с массивами всех типов, позволяя получить размер контейнера или массива в runtime.
insert_or_assign — это функция из стандартной библиотеки языка C++, добавленная в C++17. Она используется для вставки элемента в ассоциативный контейнер (например, std::map) или обновления значения элемента, если ключ уже существует.
Преимущества перед operator[]:
— Более безопасна, так как проверяет существование элемента. — Избавляет от лишнего кода для проверки наличия ключа.
#вопросы_с_собеседований Почему std::make_pair больше не нужна?
В новых стандартах C++ она утратила актуальность по нескольким причинам:
— Появились инициализаторы со скобками {} для создания std::pair напрямую. — Для вставки в контейнеры теперь есть функция emplace(), которая конструирует элемент прямо на месте. — Можно использовать агрегатную инициализацию. — Инициализаторы из C++17 позволяют сразу указывать ключ и значение.
Метод try_emplace() в C++17 - это один из способов вставки элемента в ассоциативный контейнер (например, map или unordered_map).
Позволяет вставить новый элемент по ключу, если такого ключа еще нет в контейнере. Если ключ уже существует, то ничего не происходит.
Преимущества: - Более эффективно, чем insert, т.к. сразу конструирует элемент на месте. - Не делает лишних копирований или перемещений. - Позволяет избежать ненужного перезаписывания элемента по существующему ключу.
msg_ptrэто указатель на структуру или класс, который содержит данные сообщения. Обычно это просто указатель void*. Он используется в многопоточном программировании для передачи сообщений между потоками.
Использование указателей вместо копирования данных позволяет избежать лишних копий и ускорить передачу сообщений между потоками.
Если запустить код из примера, можно увидеть, что данные успешно передаются между потоками через очередь с использованием указателей на сообщения.
Union - это специальный класс, который позволяет хранить данные разных типов в одной области памяти. Основные характеристики:
- Объявляется с ключевым словом union. - В каждый момент активно только одно поле. - Размер равен наибольшему полю. - Позволяет интерпретировать одну область памяти разными способами. - Экономит память. - Доступ к полям как в обычном классе.
std::tuple - это шаблонный класс, представляющий собой фиксированный набор элементов разных типов. Проще говоря, удобный инструмент для упаковки данных разных типов
Элементы tuple инициализируются в конструкторе и доступны только для чтения после создания.
tuple часто используется в комбинации с tie для присваивания кортежа переменным.
Рефакторинг особенно важен при работе над большими проектами, где код многократно изменяется и расширяется. Он позволяет поддерживать кодбейз чистым, современным и масштабируемым.
reference_wrapper - это класс-обёртка для ссылок из заголовочного файла<functional>. Он позволяет передавать ссылки как значения.
Основное преимущество в том, что reference_wrapper ведёт себя как ссылка, но может копироваться как значение. Это избавляет от необходимости использовать указатели в подобных сценариях.
В этом примере мы передаем ссылку на переменную value в функцию process, используя std::ref для создания объекта std::reference_wrapper. В функции process мы можем работать со ссылкой, как если бы она была передана напрямую, используя метод get() для получения самой ссылки.