std::any_cast
Класс
Чтобы получить эти данные обратно в изначальный тип, и используется
Если совместим — возвращает ссылку на данные нужного типа.
Например, если в
std::any_cast используется для приведения объектов типа std::any к конкретному типу данных во время выполнения программы. Класс
std::any может хранить данные любого типа, но при этом теряется информация о реальном типе данных. Чтобы получить эти данные обратно в изначальный тип, и используется
std::any_cast. Он проверяет, совместим ли хранимый в std::any объект с запрошенным целевым типом. Если совместим — возвращает ссылку на данные нужного типа.
Например, если в
std::any был помещен объект типа int, то с помощью std::any_cast этот int можно получить обратно в переменную типа int. Аналогично для других типов данных.#вопросы_с_собеседований
Что будет, если дважды вызвать free?
Если вызвать free два раза для одного и того же участка памяти, это приведет к неопределенному поведению программы и скорее всего к ее аварийному завершению.
При первом вызове free освобождается участок памяти и возвращается в кучу для последующего выделения.
При повторном вызове для того же участка менеджер памяти попытается освободить уже освобождённую область.
Это приведет к повреждению структур данных менеджера памяти и неопределенному поведению — от тихих ошибок вроде утечек памяти, до полного сбоя и аварийного завершения программы.
Что будет, если дважды вызвать free?
При первом вызове free освобождается участок памяти и возвращается в кучу для последующего выделения.
При повторном вызове для того же участка менеджер памяти попытается освободить уже освобождённую область.
Это приведет к повреждению структур данных менеджера памяти и неопределенному поведению — от тихих ошибок вроде утечек памяти, до полного сбоя и аварийного завершения программы.
string.back
Эта функция возвращает ссылку на последний символ строки.
Она позволяет получить доступ к последнему символу строки и при необходимости изменить его.
Возвращаемое значение имеет тип символа строки, обычно
#это_база
Эта функция возвращает ссылку на последний символ строки.
Она позволяет получить доступ к последнему символу строки и при необходимости изменить его.
Возвращаемое значение имеет тип символа строки, обычно
char или wchar_t. Если строка пустая, то поведение функции неопределенно, поэтому нужно проверять, что строка не пуста, прежде чем вызывать back().string.back часто используется в циклах для обработки символов строки с конца или для проверки последнего символа.#это_база
Исключение std::bad_any_cast
Исключение std::bad_any_cast выбрасывается при неудачной попытке приведения типа any к другому типу. Это происходит, когда тип, к которому производится приведение, не соответствует реальному типу объекта, хранящегося в
Например, если в
Это исключение позволяет обнаружить ошибки при использовании
Таким образом,
Чтобы избежать этого исключения, нужно проверять тип объекта в any с помощью
Исключение std::bad_any_cast выбрасывается при неудачной попытке приведения типа any к другому типу. Это происходит, когда тип, к которому производится приведение, не соответствует реальному типу объекта, хранящегося в
any. Например, если в
any хранится объект типа int, а мы пытаемся привести его к типу std::string, то будет выброшено исключение bad_any_cast. Это исключение позволяет обнаружить ошибки при использовании
any во время выполнения программы.Таким образом,
bad_any_cast гарантирует типобезопасность при работе с any и указывает на то, что при приведении типов была допущена ошибка. Чтобы избежать этого исключения, нужно проверять тип объекта в any с помощью
any_cast перед приведением типа.void указатели
Void указатель (
Void указатели могут приводиться к любому другому типу указателей и обратно без явного преобразования.
Арифметические операции недопустимы для void указателей, так как компилятор не знает размер объекта в памяти. При их использовании нужно следить за типобезопасностью и правильностью приведений типов.
В основном void указатели используются для обобщенной работы с указателями разных типов. Например, в функциях реализующих общие алгоритмы.
#это_база
Void указатель (
void*) — это не типизированный указатель, который может указывать на объект любого типа.Void указатели могут приводиться к любому другому типу указателей и обратно без явного преобразования.
Арифметические операции недопустимы для void указателей, так как компилятор не знает размер объекта в памяти. При их использовании нужно следить за типобезопасностью и правильностью приведений типов.
В основном void указатели используются для обобщенной работы с указателями разных типов. Например, в функциях реализующих общие алгоритмы.
#это_база
Wt
Wt — это фреймворк веб-приложений, который позволяет разработчикам создавать веб-приложения с использованием C++. Его встроенные виджеты и компоненты позволяют легко создавать сложные веб-приложения с минимальными усилиями.
Кроме того, Wt предоставляет модель событий на стороне сервера, которая позволяет разработчикам писать веб-приложения, обладающие высокой отзывчивостью и интерактивностью.
https://www.webtoolkit.eu/wt
Wt — это фреймворк веб-приложений, который позволяет разработчикам создавать веб-приложения с использованием C++. Его встроенные виджеты и компоненты позволяют легко создавать сложные веб-приложения с минимальными усилиями.
Кроме того, Wt предоставляет модель событий на стороне сервера, которая позволяет разработчикам писать веб-приложения, обладающие высокой отзывчивостью и интерактивностью.
https://www.webtoolkit.eu/wt
Удаление элементов
Для удаления элементов из контейнера list могут применяться следующие функции:
clear(p): удаляет все элементы
pop_back(): удаляет последний элемент
pop_front(): удаляет первый элемент
erase(p): удаляет элемент, на который указывает итератор p. Возвращает итератор на элемент, следующий после удаленного, или на конец контейнера, если удален последний элемент
erase(begin, end): удаляет элементы из диапазона, на начало и конец которого указывают итераторы begin и end. Возвращает итератор на элемент, следующий после последнего удаленного, или на конец контейнера, если удален последний элемент
Применение всех функций представлено на картинке.
Для удаления элементов из контейнера list могут применяться следующие функции:
clear(p): удаляет все элементы
pop_back(): удаляет последний элемент
pop_front(): удаляет первый элемент
erase(p): удаляет элемент, на который указывает итератор p. Возвращает итератор на элемент, следующий после удаленного, или на конец контейнера, если удален последний элемент
erase(begin, end): удаляет элементы из диапазона, на начало и конец которого указывают итераторы begin и end. Возвращает итератор на элемент, следующий после последнего удаленного, или на конец контейнера, если удален последний элемент
Применение всех функций представлено на картинке.
std::variant
Это фича C++17, обеспечивающая типобезопасное объединение, позволяющее хранить и манипулировать значениями разных типов в одном объекте. Она является частью стандартной библиотеки C++ и определена в заголовке
Шаблонный класс
Основными функциями
В этом примере мы создаем объект
Однако если мы попытаемся получить значение, используя неправильный тип (например,
Это фича C++17, обеспечивающая типобезопасное объединение, позволяющее хранить и манипулировать значениями разных типов в одном объекте. Она является частью стандартной библиотеки C++ и определена в заголовке
<variant>.Шаблонный класс
std::variant похож на упрощенную версию union, но с дополнительной безопасностью типов и поддержкой различных операций.Основными функциями
std::variant являются index(), valueless_by_exception(), operator=, emplace.В этом примере мы создаем объект
var, который может содержать значения типов int, float или std::string. Мы присваиваем var различные значения и получаем их с помощью std::get.Однако если мы попытаемся получить значение, используя неправильный тип (например,
std::get<int>(var), когда вариант содержит std::string), это вызовет исключение std::bad_variant_access.Curiously Recurring Template Pattern (CRTP)
CRTP предполагает использование шаблонов и наследования для достижения формы статического полиморфизма. Он позволяет производному классу наследоваться от базового, который параметризуется самим производным классом в качестве аргумента шаблона.
В данном примере класс
Функция
Когда функция
CRTP предполагает использование шаблонов и наследования для достижения формы статического полиморфизма. Он позволяет производному классу наследоваться от базового, который параметризуется самим производным классом в качестве аргумента шаблона.
В данном примере класс
Base является шаблонным классом, который принимает производный класс (Derived1 или Derived2) в качестве аргумента шаблона. Класс Base предоставляет общую функциональность или интерфейс, который может быть настроен каждым производным классом.Функция
implementation() в базовом классе определяется как невиртуальная. Внутри функции implementation() используется static_cast<Derived*>(this) для приведения указателя к типу производного класса. Это позволяет каждому производному классу предоставлять свою собственную реализацию функции implementation().Когда функция
implementation() вызывается на экземпляре производного класса, она вызывает соответствующую реализацию в этом производном классе.You Ain't Gonna Need It (YAGNI)
You Ain't Gonna Need It (Вам это не понадобится) - это принцип разработки программного обеспечения, который поощряет простоту и избегает чрезмерной инженерии. принцип YAGNI побуждает разработчиков реализовывать только те функции, которые необходимы в данный момент, а не добавлять функциональность, которая может потребоваться в будущем, но в данный момент не нужна.
Вот ключевые аспекты применения принципа YAGNI:
- Минимализм: Пишите минимальный объем кода, необходимый для выполнения непосредственных требований.
- Избегайте спекулятивной разработки: Не реализуйте функции на основе спекулятивных будущих требований.
- Рефакторинг: Перерабатывайте код, чтобы удалить все ненужные или неиспользуемые функции. Это помогает сохранить код компактным и удобным для обслуживания.
- Разработка, управляемая тестами: Пишите тесты для проверки необходимых функций, а не обширного тестирования гипотетических функциональных возможностей.
Помните, что принцип заключается не в ограничении гибкости, а в принятии обоснованных решений, основанных на реальных требованиях.
You Ain't Gonna Need It (Вам это не понадобится) - это принцип разработки программного обеспечения, который поощряет простоту и избегает чрезмерной инженерии. принцип YAGNI побуждает разработчиков реализовывать только те функции, которые необходимы в данный момент, а не добавлять функциональность, которая может потребоваться в будущем, но в данный момент не нужна.
Вот ключевые аспекты применения принципа YAGNI:
- Минимализм: Пишите минимальный объем кода, необходимый для выполнения непосредственных требований.
- Избегайте спекулятивной разработки: Не реализуйте функции на основе спекулятивных будущих требований.
- Рефакторинг: Перерабатывайте код, чтобы удалить все ненужные или неиспользуемые функции. Это помогает сохранить код компактным и удобным для обслуживания.
- Разработка, управляемая тестами: Пишите тесты для проверки необходимых функций, а не обширного тестирования гипотетических функциональных возможностей.
Помните, что принцип заключается не в ограничении гибкости, а в принятии обоснованных решений, основанных на реальных требованиях.
std::get
Функция
Она применяется, когда нужно получить доступ к элементу внутри контейнера, такого как массив, вектор, map и другие. При этом сам тип контейнера может быть обобщенным.
Это упрощает код и делает его более универсальным. Нет необходимости писать отдельный код для доступа к элементам структур.
Функция
std::get используется для получения элемента из структуры данных по указанному индексу или ключу. Она применяется, когда нужно получить доступ к элементу внутри контейнера, такого как массив, вектор, map и другие. При этом сам тип контейнера может быть обобщенным.
std::get позволяет абстрагироваться от конкретного типа контейнера и работать с элементами единообразно, указывая лишь индекс или ключ нужного элемента.Это упрощает код и делает его более универсальным. Нет необходимости писать отдельный код для доступа к элементам структур.
#вопросы_с_собеседований
В чем разница между многопоточностью и асинхронностью?
Разница между многопоточностью и асинхронностью заключается в подходе к параллельному выполнению кода.
При многопоточности создаются несколько потоков управления, которые выполняются параллельно и могут разделять общие данные.
Это позволяет эффективно использовать многоядерные процессоры, но требует синхронизации доступа к общим данным с помощью мьютексов, семафоров и т. д.
Асинхронность же основана на событийной модели — код выполняется последовательно в рамках одного потока, но части кода могут приостанавливаться в ожидании каких-либо событий (например, завершения ввода-вывода).
Это позволяет избежать сложностей синхронизации, но ограничивает возможности параллелизма.
Таким образом, многопоточность эффективнее использует ресурсы процессора, а асинхронность проще в реализации и избегает проблем синхронизации.
В чем разница между многопоточностью и асинхронностью?
При многопоточности создаются несколько потоков управления, которые выполняются параллельно и могут разделять общие данные.
Это позволяет эффективно использовать многоядерные процессоры, но требует синхронизации доступа к общим данным с помощью мьютексов, семафоров и т. д.
Асинхронность же основана на событийной модели — код выполняется последовательно в рамках одного потока, но части кода могут приостанавливаться в ожидании каких-либо событий (например, завершения ввода-вывода).
Это позволяет избежать сложностей синхронизации, но ограничивает возможности параллелизма.
Таким образом, многопоточность эффективнее использует ресурсы процессора, а асинхронность проще в реализации и избегает проблем синхронизации.
#вопросы_с_собеседований
Почему вызов container.size() перед каждой итерацией цикла является плохой практикой?
Вызов container.size() перед каждой итерацией по контейнеру не является оптимальным, так как это приводит к линейной сложности O(n).
Вместо этого лучше сохранить размер контейнера в переменную до цикла, таким образом размер вычисляется только один раз, а доступ к элементам в цикле происходит за константное время O(1).
Это позволяет избежать лишних вычислений размера на каждой итерации и улучшает производительность.
Почему вызов container.size() перед каждой итерацией цикла является плохой практикой?
Вместо этого лучше сохранить размер контейнера в переменную до цикла, таким образом размер вычисляется только один раз, а доступ к элементам в цикле происходит за константное время O(1).
Это позволяет избежать лишних вычислений размера на каждой итерации и улучшает производительность.
Почленное копирование
Почленное копирование — это копирование объекта с полным копированием его внутреннего состояния.
Оно используется для корректного копирования там, где побитовое копирование оказывается неэффективным.
Почленное копирование выполняется с помощью конструктора копирования и оператора присваивания. В них для каждого поля выполняется отдельное копирование.
Для указателей и выделенной памяти почленное копирование подразумевает выделение новой памяти и копирование данных по элементам.
Почленное копирование медленнее побитового, так как требует дополнительных операций. Зато оно корректно копирует состояние объекта.
Но, зато оно помогает избежать типичных ошибок, связанных с побитовым копированием.
Чтобы включить почленное копирование в класс, нужно определить для него конструктор копирования и оператор присваивания с нужной логикой копирования.
Можно также использовать ключевое слово
#это_база
Почленное копирование — это копирование объекта с полным копированием его внутреннего состояния.
Оно используется для корректного копирования там, где побитовое копирование оказывается неэффективным.
Почленное копирование выполняется с помощью конструктора копирования и оператора присваивания. В них для каждого поля выполняется отдельное копирование.
Для указателей и выделенной памяти почленное копирование подразумевает выделение новой памяти и копирование данных по элементам.
Почленное копирование медленнее побитового, так как требует дополнительных операций. Зато оно корректно копирует состояние объекта.
Но, зато оно помогает избежать типичных ошибок, связанных с побитовым копированием.
Чтобы включить почленное копирование в класс, нужно определить для него конструктор копирования и оператор присваивания с нужной логикой копирования.
Можно также использовать ключевое слово
copy для полей класса, чтобы компилятор автоматически сгенерировал код копирования для них.#это_база
Побитовое копирование
Побитовое копирование — копирование данных из одного объекта в другой побитно, без каких-либо преобразований.
Оно используется для копирования структур и классов. Когда мы присваиваем один объект другому того же типа, происходит побитовое копирование.
Побитовое копирование быстрее обычного копирования, так как не требует вызова конструкторов и деструкторов. Но при этом копируются все данные объекта, даже те, которые не нужны.
Чтобы предотвратить побитовое копирование для класса, можно объявить конструктор копирования и оператор присваивания
Также для предотвращения побитового копирования можно использовать ключевое слово
#это_база
Побитовое копирование — копирование данных из одного объекта в другой побитно, без каких-либо преобразований.
Оно используется для копирования структур и классов. Когда мы присваиваем один объект другому того же типа, происходит побитовое копирование.
Побитовое копирование быстрее обычного копирования, так как не требует вызова конструкторов и деструкторов. Но при этом копируются все данные объекта, даже те, которые не нужны.
Чтобы предотвратить побитовое копирование для класса, можно объявить конструктор копирования и оператор присваивания
private. Тогда компилятор выдаст ошибку при попытке копирования.Также для предотвращения побитового копирования можно использовать ключевое слово
delete для этих методов.#это_база
std::byte
Это тип с фиксированным размером в 1 байт, в отличие от
Поддерживает все операции сдвига и битовые операции
— Для представления байтовых данных без неявных преобразований типов.
— В низкоуровневом коде, работающем с памятью, регистрами и т. д.
— В криптографии и работе с сетевыми данными.
— Для явного обозначения, что переменная содержит просто байт данных.
Преимущества
— Независим от платформы, в отличие от
— Повышает читаемость кода, явно указывая на тип "байт".
— Исключает ошибки преобразования к
std::byte — это тип данных, представляющий собой байт, введенный в С++17.Это тип с фиксированным размером в 1 байт, в отличие от
char, размер которого зависит от платформы. Гарантированно не имеет знака (unsigned)Поддерживает все операции сдвига и битовые операции
std::byte используется в следующих случаях:— Для представления байтовых данных без неявных преобразований типов.
— В низкоуровневом коде, работающем с памятью, регистрами и т. д.
— В криптографии и работе с сетевыми данными.
— Для явного обозначения, что переменная содержит просто байт данных.
Преимущества
std::byte:— Независим от платформы, в отличие от
char и uint8_t.— Повышает читаемость кода, явно указывая на тип "байт".
— Исключает ошибки преобразования к
int/bool при вычислениях.Паттерн Strategy
Паттерн Strategy — это паттерн проектирования, который позволяет определять семейства связанных алгоритмов и делать их взаимозаменяемыми.
Это дает возможность выбирать конкретный алгоритм во время выполнения программы.
Основная идея паттерна Strategy заключается в том, чтобы вынести алгоритмы в отдельные классы-стратегии и передавать нужную стратегию в клиентский код.
Это паттерн используется, когда:
— Нужно использовать разные варианты одного и того же алгоритма в разных ситуациях.
— Нужно легко добавлять новые стратегии, не меняя существующий клиентский код.
— Нужно избавиться от условных операторов, выбирающих алгоритм.
Паттерн Strategy — это паттерн проектирования, который позволяет определять семейства связанных алгоритмов и делать их взаимозаменяемыми.
Это дает возможность выбирать конкретный алгоритм во время выполнения программы.
Основная идея паттерна Strategy заключается в том, чтобы вынести алгоритмы в отдельные классы-стратегии и передавать нужную стратегию в клиентский код.
Это паттерн используется, когда:
— Нужно использовать разные варианты одного и того же алгоритма в разных ситуациях.
— Нужно легко добавлять новые стратегии, не меняя существующий клиентский код.
— Нужно избавиться от условных операторов, выбирающих алгоритм.
#вопросы_с_собеседований
Что такое глубокое копирование?
Глубокое копирование (deep copy) — это создание полной копии объекта, включая все его внутренние объекты и поля.
В Java глубокое копирование нужно реализовывать вручную, так как оператор присваивания и конструктор копирования создают поверхностную копию (shallow copy).
При поверхностном копировании копируются только поля текущего объекта. Внутренние объекты не копируются, а их ссылки просто переносятся в новый объект.
При глубоком копировании рекурсивно копируются также все вложенные объекты. Это позволяет разорвать связь между исходным объектом и копией.
Для глубокого копирования в Java используют:
— Переопределение метода clone().
— Сериализацию объекта.
— Вручную рекурсивно копировать все поля и вложенные объекты.
Глубокое копирование нужно, чтобы изменения в копии объекта не влияли на оригинал. Это важно для правильной работы программы.
Что такое глубокое копирование?
В Java глубокое копирование нужно реализовывать вручную, так как оператор присваивания и конструктор копирования создают поверхностную копию (shallow copy).
При поверхностном копировании копируются только поля текущего объекта. Внутренние объекты не копируются, а их ссылки просто переносятся в новый объект.
При глубоком копировании рекурсивно копируются также все вложенные объекты. Это позволяет разорвать связь между исходным объектом и копией.
Для глубокого копирования в Java используют:
— Переопределение метода clone().
— Сериализацию объекта.
— Вручную рекурсивно копировать все поля и вложенные объекты.
Глубокое копирование нужно, чтобы изменения в копии объекта не влияли на оригинал. Это важно для правильной работы программы.