Изучаем C++. По вопросам сотрудничества: @adv_and_pr
#вопросы_с_собеседований
Чем отличается using от typedef?
Синтаксис:
- Синтаксис для создания псевдонима типа с помощью typedef
следующий: typedef
int
MyInt
— создает псевдоним типа MyInt
для типа int
.
- Синтаксис с using
выглядит следующим образом: using
MyInt
=
int
— создает псевдоним типа MyInt
для типа int
.
Возможности: using
является более мощным инструментом по сравнению с typedef
. Он может быть использован не только для создания псевдонимов типов, но также и для создания псевдонимов шаблонов, псевдонимов функций и даже для создания псевдонимов для наборов значений (enum).
Поддержка шаблонов: using
более гибкий при использовании с шаблонами. Например, можно создавать псевдонимы типов для шаблонных классов следующим образом: using
MyContainer
=
std::vector<int>
. Такой подход недоступен с помощью typedef
.
Область видимости: using
создает псевдонимы типов в текущей области видимости, что может быть полезным для устранения конфликтов имен. typedef
создает псевдонимы типов на уровне глобальной области видимости, что может вызывать проблемы с именами в больших проектах.
👩💻 Не хватает мощностей при разработке на C++?
🚀 Приглашаем на экспресс-обзор современных инструментов разработки на плюсах, который состоится 31 мая в 20:00.
📢📢 На этой встрече вы сможете обменяться опытом с экспертом, а также узнать:
🔵Как автоматизировать сборку с помощью CMake, Bazel.
🔵Что такое пакетные менеджеры Conan и vcpkg и как их использовать.
Это открытое занятие является бесплатной пробной частью онлайн-курса OTUS “C++ Developer. Professional”.
Оплата курса возможна любым удобным для вас способом.
👉Чтобы записаться на урок, пройдите вступительное тестирование: https://otus.pw/V9LS/ Нативная интеграция. Информация о продукте www.otus.ru
ТОП 3 канала для тех, кто хочет выйти на новый уровень в программировании
Этичный Хакер - Уроки по хакингу. Канал c инструкциями по взлому, деанону, социальной инженерии и созданию вирусов.
Python и 1000 программ - канал для всех, кто хочет освоить самый перспективный язык 2023 года. Гайды для новичков, шпаргалки, фишки, программы и многое другое.
IT Pirate - самый большой канал со сливами курсов. Каталог 10000+, удобная навигация по языкам и школам.
#вопросы_с_собеседований
Что такое race condition?
Race condition — это ситуация, когда результат выполнения программы зависят от того, в каком порядке выполняются отдельные потоки или процессы.
При наличии race condition несколько потоков или процессов могут обращаться к общему ресурсу или переменной и пытаться изменить ее значение одновременно. Это может привести к непредсказуемым результатам и ошибкам в программе.
Чтобы этого избежать, стоит использовать мьютексы, семафоры или атомарные операции. Они позволят скоординировать доступ к общим ресурсам и обеспечить правильную последовательность выполнения операций в многопоточной среде.
deque (double-ended queue)
deque — это контейнерный класс, в который можно эффективно добавлять и удалять элементы как с начала, так и с конца, а также получать произвольный доступ к элементам по индексу. deque
фактически является двусторонней очередью.deque
, как и vector
, поддерживает произвольный доступ к элементам контейнера, но в отличие от вектора также поддерживает добавление в начало контейнера. Кроме того, во внутренней реализации deque
при изменении размера не выделяет новый массив в памяти для вмещения нового набора элементов, а манипулирует указателями.
В этом примере мы используем функции push_front()
и push_back()
для добавления элементов в конец и начало очереди, а pop_front()
и pop_back()
для удаления первого и последнего элементов очереди numbers
.
recursive mutex
Recursive mutex представляет собой механизм синхронизации, который позволяет одному потоку захватить мьютекс несколько раз без возникновения блокировки.
При каждом захвате поток должен также освободить мьютекс соответствующее количество раз, чтобы другие потоки могли получить доступ к нему.
При использовании recursive mutex
необходимо обеспечивать баланс между захватом и освобождением мьютекса, чтобы избежать утечек ресурсов и избыточной рекурсии.
В этом примере потоки t1
и t2
запускают recursiveFunction
с разной глубиной и результат выполнения программы будет выводить глубину рекурсии, пока она не достигнет 0.
#вопросы_с_собеседований
Как работает spinlock?
Spinlock - это примитив синхронизации, который используется для организации доступа к общему ресурсу между несколькими потоками в многопоточной среде. Он работает по принципу активного ожидания (busy-waiting), когда поток, не получив доступ к ресурсу, повторно проверяет условие блокировки без перехода в режим ожидания или сна.
Основная идея spinlock состоит в том, чтобы поток, желающий получить доступ к ресурсу, повторял быструю проверку состояния блокировки в цикле, называемом "spin". Если блокировка уже удерживается другим потоком, текущий поток продолжает повторять проверку до тех пор, пока блокировка не будет освобождена.
Однако, важно отметить, что использование spinlock не всегда является эффективным. Если потоки занимаются активным ожиданием без перехода в режим ожидания, это может привести к высокому использованию процессорного времени. Spinlock особенно полезен, когда блокировки очень короткие и вероятность конфликтов невысока.
#вопросы_с_собеседований
Как размещается в памяти класс с множественным наследованием и виртуальными функциями в с++?
- Каждый класс в иерархии наследования имеет свой собственный блок памяти, называемый подобъектом базового класса.
- Порядок размещения подобъектов определяется порядком, в котором они перечислены при определении класса-наследника.
- Для каждого класса-потомка, содержащего виртуальные функции, компилятор создает таблицу виртуальных функций, она содержит указатели на виртуальные функции класса.
- У каждого объекта класса, содержащего виртуальные функции, есть указатель на его таблицу виртуальных функций (VTable pointer).
- Размер класса равен сумме размеров его подобъектов базовых классов плюс любые дополнительные данные, определенные в самом классе.
- При вызове виртуальной функции компилятор использует указатель на VTable объекта, чтобы найти правильную функцию для вызова.
*Реализация размещения таких классов может отличаться в зависимости от компилятора и платформы, на которой выполняется код. Описанный выше процесс является общим принципом, но некоторые детали могут различаться.
std::async
В C++ std::async
- это шаблон функции, предоставляемый стандартной библиотекой <future>
. Он используется для асинхронного выполнения функции или вызываемого объекта и получения объекта future, представляющего результат вычислений.
Функция std::async
создает новый поток или использует существующий поток из пула потоков реализации для выполнения поставленной задачи. Она возвращает объект std::future
, который можно использовать для получения результата или статуса вычисления.
В этом примере функция AddNumbers
выполняется асинхронно с использованием std::async
. Она принимает два целых числа в качестве аргументов и возвращает их сумму. Функция std::async
вызывается с помощью AddNumbers
и аргументов 5 и 10.
Функция std::async
возвращает объект std::future<int>
, который представляет собой результат вычисления. Вызывая функцию get()
на объекте future
, мы блокируем выполнение до завершения вычислений и получаем результат.
Базовый курс лекций по С++ из бакалавриата МФТИ
https://youtu.be/Bym7UMqpVEY?list=PL3BR09unfgciJ1_K_E914nohpiOiHnpsK
std::atomic_flagstd::atomic_flag
является классом для реализации простой атомарной флаговой переменной. Он предоставляет механизм безопасной работы с флагом в многопоточной среде без необходимости использования блокировок.std::atomic_flag
имеет два основных метода: test_and_set()
и clear()
:
Метод test_and_set()
устанавливает флаг в "истину" и возвращает предыдущее значение флага. Если флаг уже был установлен, вызов test_and_set()
вернет true
, в противном случае он вернет false
.
Метод clear()
сбрасывает флаг в "ложь".
В этом примере создаются два потока workerThread1
и workerThread2
, которые пытаются получить доступ к защищенному блоку кода. Флаг flag
инициализируется значением true
с помощью ATOMIC_FLAG_INIT
. В цикле worker()
каждый поток пытается вызвать test_and_set()
для захвата флага. Если флаг уже установлен, поток ждет и повторно пытается его захватить. Когда флаг наконец захватывается, поток выполняет некоторую работу и вызывает clear()
для освобождения флага.
std::conditional_variable
std::condition_variable является частью стандартной библиотеки и позволяет потоку ожидать наступления определенного условия перед продолжением выполнения.
Основной метод std::condition_variable
- это wait()
, который блокирует вызывающий поток до тех пор, пока другой поток не оповестит его с помощью метода notify_one()
или notify_all()
. Когда вызывается wait()
, текущий поток освобождает блокировку, которая должна быть захвачена вместе с вызовом wait()
, и ожидает, пока другой поток не вызовет один из методов оповещения. После получения оповещения поток пробуждается и пытается повторно захватить блокировку, и если блокировка успешно захватывается, поток может продолжить свою работу.
В этом примере создается поток workerThread
, который ожидает сигнала от основного потока. Основной поток засыпает на 2 секунды, а затем устанавливает флаг ready
в true
и оповещает ожидающий поток с помощью notify_one()
. workerThread
пробуждается и выводит сообщение в консоль.
⁉️ Хотите научиться писать код без копипасты? Хотите, чтобы ваши программы были масштабируемы?
⚡️Приглашаем на бесплатный вебинар онлайн-курса «Rust Developer. Basic» в Отус.
Тема открытого урока: «Особенности Rust: обобщённое программирование, полиморфизм в Rust»
🕰 Дата: 22.05 (мск) в 20:00
На уроке мы рассмотрим статический и динамический полиморфизм в Rust, которые позволяют писать красивые и эффективные программы.
Обсудим, чем подход Rust отличается от других языков.
Рассмотрим известные проблемы и вместе найдем для них решение, которое будет приятно писать и читать.
👉 Регистрация на вебинар: https://otus.pw/CZ7Q/
Протестируйте процесс обучения и приходите учиться!
Реклама. Информация о рекламодателе на сайте www.otus.ru
Что, если разработчик перерос свою должность, но не хочет быть руководителем?
О том, почему это абсолютно нормально и куда расти техническому специалисту с глубокой экспертизой, рассказывает Александр Черушников, IT-лидер Газпромбанка.
Читайте полностью на Хабре — https://vk.cc/co4JUP
#вопросы_с_собеседований
Как разработать систему плагинов на С++?
Разработка системы подключаемых модулей на C++ включает в себя создание структуры, позволяющей динамическую загрузку и обнаружение подключаемых модулей во время выполнения.
Ниже приведен обзор соответствующих шагов:
1. Определите интерфейс подключаемых модулей: Этот интерфейс должен определять набор функций или классов, которые должны реализовывать подключаемые модули.
2. API для плагинов: Создайте API, который облегчает загрузку и управление подключаемыми модулями.
3. Динамическая загрузка библиотек: Используйте механизм динамической загрузки библиотек операционной системы для загрузки подключаемых модулей во время выполнения.
4. Обнаружение плагинов: Реализуйте механизм для обнаружения и регистрации доступных подключаемых модулей во время выполнения.
5. Жизненный цикл плагина: Определите жизненный цикл плагинов, включая инициализацию, настройку и очистку.
6. Связь с плагинами: Разработайте механизм связи между приложением и подключаемыми модулями. Это может быть достигнуто с помощью вызовов функций, обратных вызовов, систем событий или передачи сообщений, в зависимости от требований вашей системы плагинов.
7. Обработка ошибок: Реализуйте механизмы обработки ошибок для разрешения таких ситуаций, как неудачная загрузка плагина, несовместимые версии плагинов или ошибки времени выполнения плагинов. Это обеспечивает надежность и стабильность системы плагинов.
Стоит отметить, что разработка системы плагинов может быть сложной задачей, и есть существующие фреймворки и библиотеки, которые могут помочь упростить этот процесс. Некоторые популярные варианты в C++ включают Boost.Extension, Poco Foundation и Qt's Plugin System. Эти фреймворки предоставляют абстракции и инструменты для создания систем плагинов и могут сэкономить время и усилия разработчиков.
Не забывайте учитывать аспекты безопасности при разработке системы подключаемых модулей, поскольку загрузка внешнего кода может привести к потенциальным уязвимостям.
Функции вместимости в строках
1. capacity() - функция возвращает ёмкость памяти, выделенную для строки, которая может быть равной или больше, чем размер самой строки. Дополнительное пространство выделяется таким образом, чтобы при добавлении новых символов в строку операции могли выполняться эффективно.
2. resize() - функция изменяет размер строки, его можно увеличивать или уменьшать.
3. length() - функция возвращает длину строки.
4. shrink_to_fit() - функция уменьшает ёмкость памяти строки, делает ее равной минимально возможной. Эта операция полезна для экономии дополнительной памяти, когда мы уверены, что больше не нужно добавлять символы.
Принцип RAIIResource
Acquisition
Is
Initialization
является важным концептом, который связывает временный срок жизни объекта с его ресурсами. Суть принципа заключается в том, что ресурсы, такие как память, файлы, сетевые соединения и т.д., должны быть приобретены при инициализации объекта и автоматически освобождены при его уничтожении.
Принцип RAII
позволяет сделать управление ресурсами более безопасным и эффективным, освобождая программиста от ручного управления ресурсами и предотвращая утечки ресурсов.
В этом примере автоматическое закрытие файла в деструкторе обеспечивает гарантированное освобождение ресурса, даже если происходит исключение.
А в функции main
файл закрывается автоматически, при выходе из блока try
.
#вопросы_с_собеседований
Что такое exception safety guarantee?
Exception safety guarantee — это гарантия, которую предоставляет код при возникновении исключительной ситуации (exception). Это означает, что код должен обрабатывать исключения таким образом, чтобы предотвратить утечку ресурсов и поддерживать объекты в согласованном состоянии.
Существует три уровня exception safety guarantee
:-
basic: Гарантирует, что нет утечек ресурсов, но в случае исключения никаких дополнительных гарантий не предоставляется, и объекты могут быть изменены или оставлены в неполноценном состоянии.-
strong: Гарантирует, что нет утечек ресурсов и объекты остаются в исходном состоянии, если исключение возникает. Если операция не может быть выполнена, объекты не изменяются.-
no-throw: Гарантирует, что операция не вызывает исключений. Это самый высокий уровень гарантии безопасности исключений.
Разработчики должны обеспечивать соответствующий уровень exception safety
для своих классов и функций, чтобы гарантировать правильное и безопасное поведение при обработке исключений.
⚙️ Курс «Реверсивный инжиниринг ПО под ОС Windows»
Старт: 5 июня
Длительность: 6 месяцев
🎓 Курс по реверсингу приложений под Windows позволяет изучить язык Ассемблера, анализировать приложения разной сложности и изучать образцы вредоносных приложений. Также рассматриваются различные техники, используемые исследователями.
ℹ️ Кому будет полезен курс:
✔️ Пентестерам, желающим лучше изучить направление реверсинга приложений
✔️ Вирусным аналитикам и исследователям кода занимающимся изучением вредоносного ПО
✔️ Программистам, разрабатывающим продукты в области ИБ или занимающимся разработкой ПО с повышенными требованиям к защищенности (промышленное, банковское ПО и т.д.)
*Для прохождения курса необходимы базовые знания реверса
🏆 Выдаём сертификат при успешной сдаче экзамена
В честь четвертой победы Codeby на Standoff, команда Академии дарит скидку 10% на оплату курса до 15 июня. Промокод: REWWIN0623
📌 Узнать подробнее о курсе
Удаление всех вхождений элемента в массив
В этом методе сдвиньте нецелевой элемент в левую сторону.
• Проверьте, является ли текущий элемент целевым элементом или нет.
• Если это целевой элемент, увеличьте переменную cnt.
• После этого элемента все нецелевые элементы сдвинутся влево с промежутком (n-cnt).
Временная сложность: O(n)
Сложность пространства: O(1)
На картинке приведена программа на C ++ для удаления всех вхождений элемента из массива с использованием оптимизированного подхода.
std::launch::deferredstd::launch::deferred
- это флаг, который может быть использован при запуске асинхронной операции с помощью std::async
. Он указывает, что операция должна быть отложена и выполнена только при вызове функции get()
на возвращаемом объекте std::future
.
Когда операция запускается с этим флагом, она не выполняется немедленно в отдельном потоке. Вместо этого операция откладывается до момента, когда вызывается get()
на объекте std::future
. В этот момент операция будет выполнена синхронно в вызывающем потоке.
В этом примере мы создаем асинхронную операцию с помощью std::async
и флага std::launch::deferred
. Операция calculateSum
складывает два числа и не имеет задержки.
Однако, когда мы вызываем std::future::get()
, операция calculateSum
будет выполнена синхронно в вызывающем потоке, а не в отдельном потоке. Это означает, что выполнение программы будет остановлено до завершения операции calculateSum
.
std::hash
Это структура шаблонного класса, определенная в заголовочном файле <functional>
. Она предоставляет хеш-функцию для хэширования различных типов данных, включая встроенные и пользовательские.std::hash
используется, например, в ассоциативных контейнерах, таких как std::unordered_map
и std::unordered_set
, для быстрого доступа к элементам по ключу.
*Для пользовательского типа данных требуется явная специализация структуры std::hash
для корректной работы хэширования.
std::launch::asyncstd::launch::async
- это один из флагов, которые можно использовать при запуске асинхронной операции с помощью std::async
. Он указывает, что операция должна быть запущена немедленно в отдельном потоке.
При использовании std::launch::async
с std::async
создается новый поток выполнения для асинхронной операции. Это означает, что операция будет выполняться параллельно с основным потоком, который вызвал std::async
. Фактическое время запуска операции зависит от реализации, но обычно она начинается сразу после вызова std::async
.
В этом примере мы создаем асинхронную операцию с помощью std::async
и флага std::launch::async
. Операция calculateSum
складывает два числа, но перед этим засыпает на 2 секунды для имитации длительной работы.
Затем мы вызываем futureSum.get()
, чтобы получить результат асинхронной операции. Если результат еще не готов, основной поток будет блокирован до его завершения.
thread-safe пул потоков
На первом изображении представлена реализация потокобезопасного пула потоков. В этой реализации класс ThreadPool
управляет коллекцией рабочих потоков. Количество рабочих потоков определяется при создании пула потоков. Функция enqueue
используется для передачи заданий в пул потоков.
На втором изображении представлен пример использования. функция Task
передается в пул потоков с помощью функции enqueue
. Функция Task
просто печатает сообщение и "спит" в течение 1 секунды. После отправки всех заданий главный поток ждет некоторое время, чтобы дать заданиям завершиться перед выходом.
Обратите внимание, что приведенный здесь код является базовой реализацией пула потоков и не включает в себя расширенные возможности, такие как обработка возвращаемых значений от задач или ограничение количества одновременных задач. Вы можете расширить эту реализацию в соответствии с вашими конкретными потребностями.
🫵 Пройди тест по C++ и проверь свои знания.
Ответишь — пройдешь на продвинутый курс "C++ Developer. Professional" от OTUS по специальной цене + получишь запись мастер-класса от преподавателя курса.
⛔️ ПРОЙТИ ТЕСТ: https://otus.pw/pLpV/Нативная интеграция. Информация о продукте www.otus.ru
Присоединяйтесь к участникам ключевого события для разработчиков инженерного программного обеспечения в России – конференции C3Days 2023.
Мероприятие проводит компания C3D Labs – создатель коммерческого геометрического ядра в России. Продукты C3D Labs используют крупнейшие отечественные разработчики CAD, MCAD, CAM, PDM, CAE, CFD систем, а также AEC и BIM решений. Среди них: Аскон (Компас-3D), Нанософт (nanoCAD), Renga Software (Renga) и др.
25-26 мая в Санкт-Петербурге C3D Labs в шестой раз соберёт ведущих математиков и программистов в области САПР, а также специалистов, которые хотят развивать свои 3D-продукты с помощью современных продуктов. Вместе они обсудят актуальные вопросы стратегии импортозамещения, познакомятся с новинками C3D Labs и опытом применения решений. Также участники смогут освоить новые навыки на мастер-классах от экспертов C3D Labs.
Знакомьтесь с программой и регистрируйтесь на сайте: https://bit.ly/455AJdG
Участие – бесплатное при предварительной регистрации.
ЕРИД: 2VtzqwdcXkV
Движок C3D Vision управляет отображением 3D-текстур «на лету»
Texture3D представляет стандартный C++ класс и служит для обработки 3D-текстур.
Смотреть статью
#вопросы_с_собеседований
Что такое CI/CD и какие преимущества дает разработчику?
CI/CD означает непрерывную интеграцию и непрерывное развертывание. Это набор практик и инструментов, используемых в разработке программного обеспечения для автоматизации процесса создания, тестирования и развертывания приложений.
Непрерывная интеграция включает в себя интеграцию изменений кода от нескольких разработчиков в общий репозиторий часто, как правило, несколько раз в день. Каждая интеграция запускает автоматизированный процесс сборки и тестирования для раннего обнаружения и решения проблем интеграции.
Непрерывное развертывание (или Continuous Delivery) направлено на автоматизацию процесса развертывания программного обеспечения в производственных средах. Он включает в себя автоматизацию шагов, необходимых для упаковки, развертывания и настройки приложения.
Вот некоторые преимущества CI/CD для разработчиков C++:
1. Раннее обнаружение ошибок.
2. Более быстрый цикл обратной связи.
3. Качество и ремонтопригодность кода.
4. Сотрудничество и коммуникация между разработчиками.
5. Автоматизация сборки, тестирования и развертывания кода.
6. Непрерывное развертывание.
7. Масштабируемость.
#вопросы_с_собеседований
Что такое барьеры памяти?
В C++ барьеры памяти являются механизмами синхронизации, используемыми для контроля порядка и видимости операций с памятью в многопоточных программах. Они гарантируют, что операции с памятью выполняются в определенном порядке и что эффекты одной операции видны другим потокам предсказуемым образом.
Существует несколько типов барьеров памяти, которые можно использовать в C++:
- Барьер приобретения: Гарантирует, что последующие операции с памятью не могут быть переупорядочены до барьера.
- Барьер освобождения: Гарантирует, что предшествующие операции с памятью не могут быть переупорядочены после барьера.
- Полный барьер памяти: Обеспечивает семантику как приобретения, так и освобождения.
- Барьер чтения-записи: Гарантирует, что предшествующие операции чтения не могут быть переупорядочены последующими операциями записи.
В C++ барьеры памяти обычно реализуются с помощью атомарных операций или примитивов синхронизации, предоставляемых языком, таких как std::atomic_thread_fence, std::atomic_signal_fence, или мьютексов и переменных состояния.
std::unordered_map
std::unordered_map - это контейнерный класс, который предоставляет структуру данных, известную как хэш-карта или хэш-таблица. Он доступен начиная с C++11.
Контейнер std::unordered_map хранит элементы в виде пар ключ-значение, где каждый ключ уникален, а производительность зависит от качества хэш-функции, используемой для сопоставления ключей с базовыми корзинами.
std::unordered_map в качестве ключей поддерживает встроенные типы, типы, определяемые пользователем, и даже структуры или классы.-
В этом примере мы создаем myMap
, которая сопоставляет целые числа со строками. -
С помощью функции insert()
вставляются 3 пары ключ-значение. -
Затем мы получаем доступ и печатаем значение, связанное с ключом 2, используя оператор []
. -
С помощью функции erase()
удаляем значение с ключом 3. -
Далее мы выполняем итерации по карте с помощью цикла for
, чтобы вывести все пары ключ-значение. -
Наконец, мы используем функцию find()
, чтобы проверить, существует ли ключ 2 в карте.