Pure virtual function
Чисто виртуальная функция объявляется путем присваивания в объявлении.
В этом примере у нас есть абстрактный базовый класс
Затем мы создаем два производных класса
В функции
Pure virtual function
(чисто виртуальная функция) — это виртуальная функция, для которой мы можем иметь реализацию, но мы должны переопределить эту функцию в производном классе, иначе производный класс также станет абстрактным классом. Чисто виртуальная функция объявляется путем присваивания в объявлении.
В этом примере у нас есть абстрактный базовый класс
Shape
, который содержит чисто виртуальную функцию draw()
. Мы не можем создать объект класса Shape
, так как он является абстрактным классом. Затем мы создаем два производных класса
Circle
и Rectangle
, которые переопределяют функцию draw()
. В функции
main()
мы создаем объекты circle
и rectangle
, а также указатель на базовый класс Shape
. Мы устанавливаем указатель на объекты circle
и rectangle
и вызываем функцию draw()
для каждого из них.Ленивые вычисления в С++
Ленивые вычисления могут быть реализованы с использованием различных подходов, таких как отложенное вычисление (
В этом примере вычисления выполняются только при первом обращении к числу Фибоначчи с определенным индексом, после чего результат сохраняется в контейнере
lazy evaluation
— это стратегия вычислений, при которой вычисления откладываются до тех пор, пока результат не станет действительно необходимым. Это позволяет оптимизировать производительность и ресурсоемкость программы, избегая ненужных вычислений.Ленивые вычисления могут быть реализованы с использованием различных подходов, таких как отложенное вычисление (
deferred evaluation
), вычисление по требованию (on-demand evaluation
) и мемоизация (memoization
).В этом примере вычисления выполняются только при первом обращении к числу Фибоначчи с определенным индексом, после чего результат сохраняется в контейнере
memo
для последующего использования. Это позволяет избежать повторных вычислений и оптимизировать производительность программы.#вопросы_с_собеседований
Как работает RTTI?
RTTI расшифровывается как "Run-Time Type Information" и является функцией в C++, которая предоставляет информацию о типе объекта во время выполнения. Она позволяет вам динамически запрашивать и манипулировать информацией о типе объекта.
В C++ информация о типе объектов обычно представлена механизмом, называемым классом type_info. Класс type_info является частью стандартной библиотеки C++ и определяется в заголовке <typeinfo>.
Чтобы использовать RTTI в C++, необходимо включить функцию RTTI, указав флаг компилятора -frtti или включив его в настройках проекта.
RTTI особенно полезен, когда у вас есть указатель на базовый класс или ссылка на объект производного класса. RTTI обеспечивает безопасную передачу указателя базового класса в производный класс и выполнение определенных операций. Для этого используется оператор dynamic_cast, который выполняет динамическое приведение и возвращает указатель или ссылку целевого типа, если приведение корректно, или нулевой указатель, или выбрасывает исключение, если приведение не удалось.
Как работает RTTI?
В C++ информация о типе объектов обычно представлена механизмом, называемым классом type_info. Класс type_info является частью стандартной библиотеки C++ и определяется в заголовке <typeinfo>.
Чтобы использовать RTTI в C++, необходимо включить функцию RTTI, указав флаг компилятора -frtti или включив его в настройках проекта.
RTTI особенно полезен, когда у вас есть указатель на базовый класс или ссылка на объект производного класса. RTTI обеспечивает безопасную передачу указателя базового класса в производный класс и выполнение определенных операций. Для этого используется оператор dynamic_cast, который выполняет динамическое приведение и возвращает указатель или ссылку целевого типа, если приведение корректно, или нулевой указатель, или выбрасывает исключение, если приведение не удалось.
#вопросы_с_собеседований
Что такое copy elision и когда становится возможным? Какие особенности для разных стандартов?
copy elision - это техника оптимизации компилятора в C++, которая позволяет устранить ненужные операции копирования или перемещения при возврате объектов из функций или инициализации объектов. Это позволяет компилятору оптимизировать создание и уничтожение временных объектов, в результате чего код становится более эффективным.
copy elision становится возможной в сценариях, определенных стандартом C++. Соответствующее положение стандарта называется правилом "as-if", которое позволяет компилятору оптимизировать программу до тех пор, пока она производит такое же наблюдаемое поведение, как и исходный код.
- C++98/03: copy elision не является обязательной, но разрешена в качестве оптимизации. RVO* и NRVO* - обычные оптимизации, выполняемые компиляторами. *(Return Value Optimization, Named Return Value Optimization)
- C++11: Правила copy elision были пересмотрены. RVO и NRVO стали обязательными в некоторых случаях. copy elision также может происходить при выбросе исключений.
- C++17: Правила исключения копирования были еще более смягчены. Именованные переменные могут быть созданы или присвоены без необходимости выполнения операции перемещения. Эта оптимизация называется "mandatory copy elision".
- C++20: Правила исключения копирования остались такими же, как и в C++17.
Важно отметить, что хотя копирование является широко поддерживаемой оптимизацией, оно все еще зависит от реализации компилятором. Компиляторы могут иметь различное поведение или ограничения в отношении copy elision. Поэтому её использование для оптимизации поведения или производительности может быть непереносимым в различных компиляторах или версиях.
Что такое copy elision и когда становится возможным? Какие особенности для разных стандартов?
copy elision становится возможной в сценариях, определенных стандартом C++. Соответствующее положение стандарта называется правилом "as-if", которое позволяет компилятору оптимизировать программу до тех пор, пока она производит такое же наблюдаемое поведение, как и исходный код.
- C++98/03: copy elision не является обязательной, но разрешена в качестве оптимизации. RVO* и NRVO* - обычные оптимизации, выполняемые компиляторами. *(Return Value Optimization, Named Return Value Optimization)
- C++11: Правила copy elision были пересмотрены. RVO и NRVO стали обязательными в некоторых случаях. copy elision также может происходить при выбросе исключений.
- C++17: Правила исключения копирования были еще более смягчены. Именованные переменные могут быть созданы или присвоены без необходимости выполнения операции перемещения. Эта оптимизация называется "mandatory copy elision".
- C++20: Правила исключения копирования остались такими же, как и в C++17.
Важно отметить, что хотя копирование является широко поддерживаемой оптимизацией, оно все еще зависит от реализации компилятором. Компиляторы могут иметь различное поведение или ограничения в отношении copy elision. Поэтому её использование для оптимизации поведения или производительности может быть непереносимым в различных компиляторах или версиях.
Алгоритм fill_n
Алгоритм используется для заполнения некоторых значений по умолчанию в контейнере.
Он принимает начало итератора и количество позиций n в качестве аргументов и заполняет первую позицию n , начиная с позиции, указанной параметром begin , заданным значением.
Синтаксис:
Алгоритм используется для заполнения некоторых значений по умолчанию в контейнере.
Он принимает начало итератора и количество позиций n в качестве аргументов и заполняет первую позицию n , начиная с позиции, указанной параметром begin , заданным значением.
Синтаксис:
void fill_n (начало итератора, int n, значение типа);
std::reference_wrapper
Основное назначение
#для_начинающих
std::reference_wrapper
— это класс в C++, предоставляемый стандартной библиотекой, который оборачивает ссылку на объект. Этот класс полезен, когда вам нужно передать или хранить ссылку на объект, но вы хотите избежать неявного копирования объекта.Основное назначение
std::reference_wrapper
заключается в том, чтобы позволить передавать ссылки как аргументы функций, которые обычно ожидают копии объектов. Это особенно полезно, например, при использовании алгоритмов из стандартной библиотеки, которые могут копировать элементы контейнера, если не явно указано иначе.#для_начинающих
insert_or_assign
#для_начинающих
insert_or_assign
является методом контейнера std::map
и std::unordered_map
(и их многих других вариантов), который был добавлен в стандарт C++17. Этот метод вставляет новый элемент или обновляет существующий элемент с указанным ключом.#для_начинающих
std::make_pair
Пример на картинке создает пару значений (
#для_начинающих
std::make_pair
— это шаблонная функция в стандартной библиотеке C++, предназначенная для создания объекта std::pair
. std::pair
— это структура, предназначенная для хранения пары значений (двух элементов) различных типов данных.Пример на картинке создает пару значений (
a
и b)
с использованием std::make_pair
и выводит их на экран. Функция make_pair
автоматически определяет типы элементов и возвращает объект std::pair
с этими значениями.#для_начинающих
Рекурсивный мьютекс
Рекурсивный мьютекс (recursive mutex) — это специальный тип мьютекса, который позволяет одному и тому же потоку многократно захватывать мьютекс, не приводя к блокировке. Это полезно в ситуациях, когда один и тот же поток может вызывать функции, которые используют мьютекс, несколько раз вложено, и без рекурсивных мьютексов это могло бы привести к блокировке потока.
В C++ стандартная библиотека предоставляет класс
Обратите внимание, что необходимо быть осторожным при использовании рекурсивных мьютексов, чтобы избежать возможных проблем с блокировкой и дедлоками.
#для_продвинутых
Рекурсивный мьютекс (recursive mutex) — это специальный тип мьютекса, который позволяет одному и тому же потоку многократно захватывать мьютекс, не приводя к блокировке. Это полезно в ситуациях, когда один и тот же поток может вызывать функции, которые используют мьютекс, несколько раз вложено, и без рекурсивных мьютексов это могло бы привести к блокировке потока.
В C++ стандартная библиотека предоставляет класс
std::recursive_mutex
для работы с рекурсивными мьютексами. Код с примера создает два потока, каждый из которых вызывает функцию foo
, которая захватывает рекурсивный мьютекс несколько раз. Благодаря рекурсивному мьютексу, это не вызывает блокировки, и программа корректно работает.Обратите внимание, что необходимо быть осторожным при использовании рекурсивных мьютексов, чтобы избежать возможных проблем с блокировкой и дедлоками.
#для_продвинутых
Минимальный и максимальный элементы
Функции
Здесь находим мин и макс элементы вектора
Так как диапазон поиска значений может быть только частью контейнера, ограниченной итераторами, то мы можем найти макс/мин значения на каком-то определенном диапазоне:
Функции
std::min_element
и std::max_element
возвращают минимальный и максимальный элементы соответственно из диапазона. В качестве коллекции элементов может выступать контейнер или массив. Диапазон элементов задается начальным и конечным итераторами контейнера/массива.Здесь находим мин и макс элементы вектора
numbers
. В обоих случаях в качестве диапазона выступает весь контейнер — от итератора begin(numbers)
до итератора end(numbers)
. Результатом каждой функции также является итератор. Потому для получения значения (максимального/минимального значения) применяем операцию разыменования: *std::min_element(...)
.Так как диапазон поиска значений может быть только частью контейнера, ограниченной итераторами, то мы можем найти макс/мин значения на каком-то определенном диапазоне:
std::cout << "Min: " << *std::min_element(begin(numbers), end(numbers)) << std::endl;#для_продвинутых
std::cout << "Max: " << *std::max_element(begin(numbers), end(numbers)) << std::endl;
std::memory_order_acquire
#для_продвинутых
std::memory_order_acquire
— это один из флагов (memory order) в стандартной библиотеке C++, который используется в контексте многопоточности и атомарных операций. Он указывает, что операция должна выполняться с учетом уровня доступа к памяти, который предписывает, что все чтения, выполняемые перед этой операцией, должны быть завершены до того, как она начнется. Это означает, что все изменения, сделанные в памяти другими потоками, должны быть видимы для текущей операции.std::memory_order_acquire
применяется обычно к операциям чтения (например, чтение значения из разделяемой переменной), чтобы гарантировать корректное чтение данных из разделяемой памяти в многопоточной среде. В сочетании с std::memory_order_release
, этот флаг может использоваться для создания атомарных операций с соблюдением необходимых гарантий согласованности памяти в многопоточной среде.#для_продвинутых
В C++ метод
std::vector::insert
позволяет вставлять элементы или диапазоны элементов в вектор на указанную позицию. Это полезно для динамического изменения содержимого контейнера.Please open Telegram to view this post
VIEW IN TELEGRAM
Директива define
Директива define используется для создания макросов, которые позволяют вам задавать символьные константы или небольшие фрагменты кода, которые будут заменены компилятором на определенное значение или код перед компиляцией программы. Это представляет собой форму текстовой подстановки.
Следует помнить, что использование макросов может иметь как положительные, так и отрицательные стороны. Они могут улучшить читаемость и обслуживаемость кода, но также могут привести к неожиданным проблемам, таким как ошибки из-за неправильной обработки аргументов макроса или проблемы с пространством имен. В C++ также есть более современные способы достижения тех же целей, такие как константы и inline функции, которые иногда предпочтительнее использовать вместо макросов.
Директива define используется для создания макросов, которые позволяют вам задавать символьные константы или небольшие фрагменты кода, которые будут заменены компилятором на определенное значение или код перед компиляцией программы. Это представляет собой форму текстовой подстановки.
Следует помнить, что использование макросов может иметь как положительные, так и отрицательные стороны. Они могут улучшить читаемость и обслуживаемость кода, но также могут привести к неожиданным проблемам, таким как ошибки из-за неправильной обработки аргументов макроса или проблемы с пространством имен. В C++ также есть более современные способы достижения тех же целей, такие как константы и inline функции, которые иногда предпочтительнее использовать вместо макросов.
static_assert
#для_начинающих
static_assert
— это механизм в C++, который позволяет выполнять проверки на этапе компиляции для статических условий. Он был добавлен в стандарт C++11 и предоставляет способ проверки, что определенное условие истинно во время компиляции. Если условие ложно, компиляция завершится ошибкой.#для_начинающих
Встраиваемые функции
Встраиваемые функции (inline functions) представляют собой специальный механизм оптимизации, который позволяет компилятору вставлять код функции непосредственно в место её вызова, вместо фактического вызова функции. Это может уменьшить накладные расходы на вызов функции и улучшить производительность программы, особенно для небольших функций.
#для_начинающих
Встраиваемые функции (inline functions) представляют собой специальный механизм оптимизации, который позволяет компилятору вставлять код функции непосредственно в место её вызова, вместо фактического вызова функции. Это может уменьшить накладные расходы на вызов функции и улучшить производительность программы, особенно для небольших функций.
#для_начинающих