#вопросы_с_собеседований
Чем отличается конструктор копирования от оператора присваивания?
Конструктор копирования:
— Вызывается при создании нового объекта на основе существующего.
— Имеет сигнатуру ClassName(const ClassName&).
— Обычно выполняет полное копирование данных из одного объекта в другой.
Оператор присваивания:
— Вызывается при присваивании значений между существующими объектами.
— Имеет сигнатуру ClassName& operator=(const ClassName&).
— Часто выполняет поверхностное копирование, присваивая ресурсы.
Различия:
— Конструктор копирования создает новый объект, оператор присваивания — нет.
— Конструктор вызывается автоматически, оператор — явно программистом.
— Конструктор вызывается один раз, оператор может вызываться многократно.
Чем отличается конструктор копирования от оператора присваивания?
— Вызывается при создании нового объекта на основе существующего.
— Имеет сигнатуру ClassName(const ClassName&).
— Обычно выполняет полное копирование данных из одного объекта в другой.
Оператор присваивания:
— Вызывается при присваивании значений между существующими объектами.
— Имеет сигнатуру ClassName& operator=(const ClassName&).
— Часто выполняет поверхностное копирование, присваивая ресурсы.
Различия:
— Конструктор копирования создает новый объект, оператор присваивания — нет.
— Конструктор вызывается автоматически, оператор — явно программистом.
— Конструктор вызывается один раз, оператор может вызываться многократно.
#вопросы_с_собеседований
Зачем делать explicit-конструктор?
Explicit-конструктор используется для преобразования типов с явным указанием желаемого типа. Это позволяет избежать неявных преобразований и потенциальных ошибок.
Основные причины использовать explicit-конструктора:
— Предотвратить неявные преобразования, которые могут привести к потере данных.
— Избежать вызова конструктора при копировании объекта.
— Принудительно вызывать конструктор только при явном преобразовании типов.
— Улучшить читаемость кода, делая преобразования типов очевидными.
Зачем делать explicit-конструктор?
Основные причины использовать explicit-конструктора:
— Предотвратить неявные преобразования, которые могут привести к потере данных.
— Избежать вызова конструктора при копировании объекта.
— Принудительно вызывать конструктор только при явном преобразовании типов.
— Улучшить читаемость кода, делая преобразования типов очевидными.
Алгоритм is_partitioned
Алгоритм is_partitioned — это алгоритм из стандартной библиотеки algorithm, который проверяет, разбит ли диапазон элементов определенным образом.
Принимает три параметра:
— Два итератора, задающих проверяемый диапазон.
— Предикат (функцию или функтор), определяющий разбиение.
Возвращает bool значение — true если диапазон разбит согласно предикату и false в противном случае.
Этот алгоритм предпочтительнее цикла, т. к. проще в использовании и читабельнее, ведь он эффективно проверяет условие за один проход по последовательности.
В примере мы определяем предикат isEven для проверки четности числа, передаем его в is_partitioned вместе с вектором v и выводим результат.
#это_база
Алгоритм is_partitioned — это алгоритм из стандартной библиотеки algorithm, который проверяет, разбит ли диапазон элементов определенным образом.
Принимает три параметра:
— Два итератора, задающих проверяемый диапазон.
— Предикат (функцию или функтор), определяющий разбиение.
Возвращает bool значение — true если диапазон разбит согласно предикату и false в противном случае.
Этот алгоритм предпочтительнее цикла, т. к. проще в использовании и читабельнее, ведь он эффективно проверяет условие за один проход по последовательности.
В примере мы определяем предикат isEven для проверки четности числа, передаем его в is_partitioned вместе с вектором v и выводим результат.
#это_база
Функция minmax_element
Функция minmax_element — это алгоритм из стандартной библиотеки algorithm, который позволяет найти минимальный и максимальный элементы в диапазоне.
Функция принимает два итератора, задающих диапазон поиска и возвращает пару итераторов на минимальный и максимальный элементы. Работает для любых типов данных, поддерживающих операцию сравнения <.
Некоторые характеристики:
— Позволяет найти границы диапазона за один проход по последовательности.
— Удобна при необходимости найти пределы в контейнере или массиве.
— Предпочтительнее циклов, т. к. проще в использовании и читабельнее.
— Может применяться со стандартными контейнерами, векторами, списками.
#это_база
Функция minmax_element — это алгоритм из стандартной библиотеки algorithm, который позволяет найти минимальный и максимальный элементы в диапазоне.
Функция принимает два итератора, задающих диапазон поиска и возвращает пару итераторов на минимальный и максимальный элементы. Работает для любых типов данных, поддерживающих операцию сравнения <.
Некоторые характеристики:
— Позволяет найти границы диапазона за один проход по последовательности.
— Удобна при необходимости найти пределы в контейнере или массиве.
— Предпочтительнее циклов, т. к. проще в использовании и читабельнее.
— Может применяться со стандартными контейнерами, векторами, списками.
#это_база
std::data
std::data — это стандартная функция, которая возвращает указатель на недоступное буферное хранилище контейнера.
Она используется для непосредственного доступа к данным контейнера в памяти.
Основные применения:
— Прямой доступ к элементам массива или вектора для чтения/записи.
— Передача данных контейнера в функции, принимающие указатель в качестве аргумента.
— Выполнение операций, зависящих от порядка элементов в памяти.
— Оптимизации производительности за счёт избежания копирования.
— Низкоуровневые операции и интеграция с кодом на С.
— Итерация элементов в порядке хранения.
std::data — это стандартная функция, которая возвращает указатель на недоступное буферное хранилище контейнера.
Она используется для непосредственного доступа к данным контейнера в памяти.
Основные применения:
— Прямой доступ к элементам массива или вектора для чтения/записи.
— Передача данных контейнера в функции, принимающие указатель в качестве аргумента.
— Выполнение операций, зависящих от порядка элементов в памяти.
— Оптимизации производительности за счёт избежания копирования.
— Низкоуровневые операции и интеграция с кодом на С.
— Итерация элементов в порядке хранения.
string at()
std::string::at() — это метод для доступа к символу строки по указанному индексу.
Принимает в качестве аргумента индекс символа типа size_t и возвращает ссылку на символ по данному индексу.
— Индексация начинается с 0 до size()-1.
— Выбрасывает исключение out_of_range, если индекс вне диапазона.
— Более безопасен, чем оператор [], так как проверяет границы.
Полезен в циклах для доступа к каждому символу, когда нужен безопасный доступ для чтения/записи конкретного символа.
#это_база
std::string::at() — это метод для доступа к символу строки по указанному индексу.
Принимает в качестве аргумента индекс символа типа size_t и возвращает ссылку на символ по данному индексу.
— Индексация начинается с 0 до size()-1.
— Выбрасывает исключение out_of_range, если индекс вне диапазона.
— Более безопасен, чем оператор [], так как проверяет границы.
Полезен в циклах для доступа к каждому символу, когда нужен безопасный доступ для чтения/записи конкретного символа.
#это_база
Лямбда-выражения
Лямбда-выражения (lambda) — это безымянные функции, которые можно использовать для передачи поведения или сравнения.
Объявляются как {body;}, в квадратных скобках указываются аргументы, в фигурных — тело.
Полезны для задания функций сравнения, например в алгоритмах sort(), когда нужно быстро передать функциональность, не создавая отдельную функцию.
Поддерживают захват по значению [=] и по ссылке [&].
Можно сохранить в переменной с помощью auto.
#это_база
Лямбда-выражения (lambda) — это безымянные функции, которые можно использовать для передачи поведения или сравнения.
Объявляются как {body;}, в квадратных скобках указываются аргументы, в фигурных — тело.
Полезны для задания функций сравнения, например в алгоритмах sort(), когда нужно быстро передать функциональность, не создавая отдельную функцию.
Поддерживают захват по значению [=] и по ссылке [&].
Можно сохранить в переменной с помощью auto.
#это_база
#вопросы_с_собеседований
Для чего нужен атрибут maybe_unused?
Атрибут [[maybe_unused]] используется для подавления предупреждений компилятора об неиспользуемых объектах.
Компилятор выдает предупреждение, если объект объявлен, но нигде не используется и чтобы избавиться от ложных предупреждений, например, когда объект используется только в отладочной сборке, применяют [[maybe_unused]].
Позволяет задать политику использования на уровне отдельных объектов и улучшает читаемость кода, явно объясняя причину неиспользования.
Для чего нужен атрибут maybe_unused?
Компилятор выдает предупреждение, если объект объявлен, но нигде не используется и чтобы избавиться от ложных предупреждений, например, когда объект используется только в отладочной сборке, применяют [[maybe_unused]].
Позволяет задать политику использования на уровне отдельных объектов и улучшает читаемость кода, явно объясняя причину неиспользования.
#вопросы_с_собеседований
Для чего нужен атрибут fallthrough?
Атрибут [[fallthrough]] используется для явного указания того, что в конструкции switch нужно пропустить break в конце case и перейти к выполнению следующего case.
По умолчанию в С++17 и новее переход между case без break приводит к ошибке компиляции и чтобы сохранить старое поведение и разрешить переход, нужно добавить [[fallthrough]].
Это улучшает читаемость кода, явно указывая на отсутствие break и помогает избежать случайного отсутствия break, когда разработчик забыл его добавить.
[[fallthrough]] также полезен при рефакторинге старого кода с switch в современный стандарт С++.
Для чего нужен атрибут fallthrough?
По умолчанию в С++17 и новее переход между case без break приводит к ошибке компиляции и чтобы сохранить старое поведение и разрешить переход, нужно добавить [[fallthrough]].
Это улучшает читаемость кода, явно указывая на отсутствие break и помогает избежать случайного отсутствия break, когда разработчик забыл его добавить.
[[fallthrough]] также полезен при рефакторинге старого кода с switch в современный стандарт С++.
#вопросы_с_собеседований
Может ли inline-функция быть рекурсивной?
Поскольку компилятор просто встраивает код inline-функции в место вызова, не имеет значения, является ли эта функция рекурсивной или нет. Компилятор будет просто копировать один и тот же код функции при каждом рекурсивном вызове.
Таким образом, рекурсивные inline-функции абсолютно допустимы и часто используются, когда нужна рекурсия без накладных расходов на стандартные вызовы функций.
Может ли inline-функция быть рекурсивной?
Таким образом, рекурсивные inline-функции абсолютно допустимы и часто используются, когда нужна рекурсия без накладных расходов на стандартные вызовы функций.
Алгоритм generate
std::generate — это алгоритм из стандартной библиотеки C++, который используется для заполнения диапазона элементов сгенерированными значениями.
Принимает три параметра: начало диапазона, конец диапазона и функцию генерации. Функция генерации должна принимать неявный счетчик и возвращать очередное значение.
Для каждого элемента в заданном диапазоне будет вызываться функция генерации, и результат будет записан в этот элемент.
В этом примере std::generate совместно с генератором случайных чисел используется для быстрого заполнения вектора случайными значениями.
#это_база
std::generate — это алгоритм из стандартной библиотеки C++, который используется для заполнения диапазона элементов сгенерированными значениями.
Принимает три параметра: начало диапазона, конец диапазона и функцию генерации. Функция генерации должна принимать неявный счетчик и возвращать очередное значение.
Для каждого элемента в заданном диапазоне будет вызываться функция генерации, и результат будет записан в этот элемент.
В этом примере std::generate совместно с генератором случайных чисел используется для быстрого заполнения вектора случайными значениями.
#это_база
std::clamp
std::clamp — это функция из стандартной библиотеки, которая позволяет ограничить значение в заданном диапазоне.
Функция принимает значение, нижнюю и верхнюю границы и возвращает исходное значение, если оно входит в диапазон, или же возвращает ближайшую границу, если значение вне диапазона.
Применяется для:
— Ограничения числовых значений в заданных пределах.
— Обработки данных из недостоверных источников.
— Защиты от переполнения/обрезания данных.
— Нормализации данных в ML и компьютерном зрении.
— Реализации игровой логики в движках.
— Обработки аудио- и видео- сигналов.
std::clamp — это функция из стандартной библиотеки, которая позволяет ограничить значение в заданном диапазоне.
Функция принимает значение, нижнюю и верхнюю границы и возвращает исходное значение, если оно входит в диапазон, или же возвращает ближайшую границу, если значение вне диапазона.
Применяется для:
— Ограничения числовых значений в заданных пределах.
— Обработки данных из недостоверных источников.
— Защиты от переполнения/обрезания данных.
— Нормализации данных в ML и компьютерном зрении.
— Реализации игровой логики в движках.
— Обработки аудио- и видео- сигналов.
absl::btree
absl::btree — это реализация B-дерева в библиотеке Abseil для C++.
Преимущества absl::btree — это хранение данных в отсортированном порядке, быстрый поиск, вставка и удаление за O(logN), поддержка уникальных и неуникальных ключей, реализация set и map.
Применяется в задачах, где нужна высокопроизводительная структура данных с отсортированным доступом, например:
Реализация словарей и сортированных множеств;
Для хранения данных в базах данных;
В поисковых системах для индексов;
В структурах вроде кэша для быстрого доступа;
В задачах машинного обучения для хранения данных.
absl::btree — это реализация B-дерева в библиотеке Abseil для C++.
Преимущества absl::btree — это хранение данных в отсортированном порядке, быстрый поиск, вставка и удаление за O(logN), поддержка уникальных и неуникальных ключей, реализация set и map.
Применяется в задачах, где нужна высокопроизводительная структура данных с отсортированным доступом, например:
Реализация словарей и сортированных множеств;
Для хранения данных в базах данных;
В поисковых системах для индексов;
В структурах вроде кэша для быстрого доступа;
В задачах машинного обучения для хранения данных.
#вопросы_с_собеседований
Какие отличия у std::array и std::vector?
std::array — это обёртка вокруг обычного массива, фиксированного размера, а std::vector - это динамически расширяемый массив. std::array хранит свои данные в стековой памяти, а vector выделяет память в куче (динамическая память). У std::array в параметрах шаблона указывается тип хранимых элементов и размер массива. А у std::vector - тип элементов и ещё возможно указать аллокатор, который нужно использовать при выделении памяти (с помощью new). std::array чуть лучше по производительности в случае небольшого массива, чем std::vector, который содержит в себе несколько указателей, которые указывают на выделенный в куче кусок памяти.
Какие отличия у std::array и std::vector?
#вопросы_с_собеседований
Что быстрее: постфиксные инкрементные операторы или префиксные? Чем отличается их сигнатура?
Префиксные операторы быстрее. В постфиксных операторах производится дополнительная операция сохранения предыдущего состояния объекта, а затем только увеличение на 1, а в префиксном операторе после инкрементирования объекта, сразу возвращается ссылка объект.
Сигнатура их отличается фиктивным параметром int у постфиксного оператора.
Что быстрее: постфиксные инкрементные операторы или префиксные? Чем отличается их сигнатура?
Префиксные операторы быстрее. В постфиксных операторах производится дополнительная операция сохранения предыдущего состояния объекта, а затем только увеличение на 1, а в префиксном операторе после инкрементирования объекта, сразу возвращается ссылка объект.
Сигнатура их отличается фиктивным параметром int у постфиксного оператора.
this удобно использовать для цепочных вызовов
Мы можем вернуть ссылку на объект, на котором мы вызываем метод класса:
Здесь метод set возвращает ссылку на объект класса Foo(Foo&). Такая реализация метода позволяет нам писать код, подобный этому:
Это возможно, поскольку первый вызов метода set возвращает указатель на объект obj. Второй метод вызывается на объекте obj, т. е. можно переписать код так:
Мы можем вернуть ссылку на объект, на котором мы вызываем метод класса:
Foo &set(int x) { this->x = x; return *this; }
Здесь метод set возвращает ссылку на объект класса Foo(Foo&). Такая реализация метода позволяет нам писать код, подобный этому:
obj.set(2).set(8);
Это возможно, поскольку первый вызов метода set возвращает указатель на объект obj. Второй метод вызывается на объекте obj, т. е. можно переписать код так:
obj = obj.set(2);
obj = obj.set(8);Указатель this доступен только внутри нестатических методов класса
Попробуем добавить такой метод в наш класс:
Здесь мы добавили для метода setмодификатор static.
Это объясняется тем, что указатель this передаётся только в нестатические методы класса как скрытый параметр. В статических методах он недоступен.
Попробуем добавить такой метод в наш класс:
static void set(int x) { this->x = x; }
Здесь мы добавили для метода setмодификатор static.
obj.set(6);
Мы получим ошибку компиляции: ‘this’ is unavailable for static member functions.Это объясняется тем, что указатель this передаётся только в нестатические методы класса как скрытый параметр. В статических методах он недоступен.
Продвинутый курс лекций по алгоритмам с ФИВТ МФТИ.
https://youtube.com/playlist?list=PL4_hYwCyhAvYzrbNOLAy-EczKdAbWoRDK
https://youtube.com/playlist?list=PL4_hYwCyhAvYzrbNOLAy-EczKdAbWoRDK