Dependency Injection
Dependency Injection (DI) — это паттерн проектирования, который позволяет управлять зависимостями между объектами. Он помогает разделить создание объектов от их использования и обеспечить более гибкую и тестируемую архитектуру программы.
В DI объекты получают свои зависимости не напрямую, а через внешний источник, который их предоставляет. Этот источник называется контейнером внедрения зависимостей. Контейнер отвечает за создание и управление зависимостями, а объекты получают их через конструкторы, методы или свойства.
Dependency Injection (DI) — это паттерн проектирования, который позволяет управлять зависимостями между объектами. Он помогает разделить создание объектов от их использования и обеспечить более гибкую и тестируемую архитектуру программы.
В DI объекты получают свои зависимости не напрямую, а через внешний источник, который их предоставляет. Этот источник называется контейнером внедрения зависимостей. Контейнер отвечает за создание и управление зависимостями, а объекты получают их через конструкторы, методы или свойства.
паттерн Observer
Это паттерн проектирования, который позволяет объектам автоматически оповещать другие объекты об изменениях в своем состоянии. В этом паттерне есть два основных компонента: наблюдаемый объект (
Когда состояние наблюдаемого объекта изменяется, все зарегистрированные наблюдатели уведомляются об этом изменении и автоматически обновляются.
В этом примере, когда вызывается метод
Это паттерн проектирования, который позволяет объектам автоматически оповещать другие объекты об изменениях в своем состоянии. В этом паттерне есть два основных компонента: наблюдаемый объект (
subject) и наблюдатели (observers).Когда состояние наблюдаемого объекта изменяется, все зарегистрированные наблюдатели уведомляются об этом изменении и автоматически обновляются.
В этом примере, когда вызывается метод
setData, он обновляет данные и вызывает метод notifyObservers, он уведомляет всех зарегистрированных наблюдателей, вызывая update и передавая новые данные.move constructor
Move-конструктор — это специальный конструктор, который позволяет эффективно перемещать ресурсы из одного объекта в другой, без необходимости копирования данных. Он используется для реализации семантики перемещения (
Move-конструктор принимает
Использование move-конструктора позволяет избежать лишних копирований данных и повысить производительность при работе с большими или ресурсоемкими объектами.
Move-конструктор — это специальный конструктор, который позволяет эффективно перемещать ресурсы из одного объекта в другой, без необходимости копирования данных. Он используется для реализации семантики перемещения (
move semantics) и оптимизации работы с временными объектами.Move-конструктор принимает
rvalue ссылку (&&) на объект, который будет перемещен, и выполняет простое копирование указателей на данные, а не их фактическое копирование.Использование move-конструктора позволяет избежать лишних копирований данных и повысить производительность при работе с большими или ресурсоемкими объектами.
#вопросы_с_собеседований
Что такое критическая секция?
Критическая секция - это участок кода, в котором происходит доступ к общему ресурсу (например, переменной или структуре данных), и который должен быть выполнен атомарно, то есть без возможности прерывания другими потоками.
Для обеспечения безопасного доступа к критической секции в C++ используются механизмы синхронизации, такие как мьютексы (
Использование критических секций и мьютексов позволяет избежать состояний гонки (race conditions) и обеспечить корректную и безопасную работу с общими данными в многопоточных приложениях.
Что такое критическая секция?
Критическая секция - это участок кода, в котором происходит доступ к общему ресурсу (например, переменной или структуре данных), и который должен быть выполнен атомарно, то есть без возможности прерывания другими потоками.
Для обеспечения безопасного доступа к критической секции в C++ используются механизмы синхронизации, такие как мьютексы (
std::mutex) и блокировки (std::lock_guard, std::unique_lock). Перед выполнением критической секции поток должен захватить мьютекс, блокируя его для других потоков. После завершения работы в критической секции мьютекс освобождается, позволяя другим потокам получить доступ к ресурсу.Использование критических секций и мьютексов позволяет избежать состояний гонки (race conditions) и обеспечить корректную и безопасную работу с общими данными в многопоточных приложениях.
Visitor
Visitor является поведенческим паттерном проектирования, который позволяет добавлять новые операции к классам объектов, не изменяя их структуру. Он достигается путем выделения операций в отдельный класс-посетитель, который посещает объекты классов и выполняет необходимые операции.
Основная идея паттерна Visitor заключается в том, чтобы объекты классов принимали "посетителя" и передавали себя в качестве аргумента методам "посетителя", соответствующим своему классу. "Посетитель", в свою очередь, реализует различные методы для обработки разных типов объектов.
Visitor является поведенческим паттерном проектирования, который позволяет добавлять новые операции к классам объектов, не изменяя их структуру. Он достигается путем выделения операций в отдельный класс-посетитель, который посещает объекты классов и выполняет необходимые операции.
Основная идея паттерна Visitor заключается в том, чтобы объекты классов принимали "посетителя" и передавали себя в качестве аргумента методам "посетителя", соответствующим своему классу. "Посетитель", в свою очередь, реализует различные методы для обработки разных типов объектов.
std::set
Представляет собой контейнер, который содержит уникальные элементы, расположенные в отсортированном порядке. Он реализован в виде сбалансированного дерева (обычно красно-черного дерева), что обеспечивает высокую эффективность операций вставки, удаления и поиска элементов.
Некоторые особенности
Представляет собой контейнер, который содержит уникальные элементы, расположенные в отсортированном порядке. Он реализован в виде сбалансированного дерева (обычно красно-черного дерева), что обеспечивает высокую эффективность операций вставки, удаления и поиска элементов.
Некоторые особенности
std::set:- Уникальность элементов: Каждый элемент в std::set является уникальным, в контейнере не может быть несколько одинаковых элементов.- Сортировка элементов: std::set автоматически сортирует элементы по их значениям при вставке, это позволяет эффективно выполнять операции поиска.- Динамическое изменение: std::set позволяет добавлять и удалять элементы из контейнера в любое время.std::map
Представляет собой ассоциативный контейнер, который содержит пары ключ-значение, где каждый ключ уникален.
Особенности
Представляет собой ассоциативный контейнер, который содержит пары ключ-значение, где каждый ключ уникален.
Особенности
std::map в сравнении с std::set:- std::map является контейнером, который хранит пары ключ-значение, где каждый ключ уникален, в отличие от std::set, который хранит уникальные значения без дополнительных значений.- В std::map операции вставки, удаления, поиска элементов, а также автоматической сортировки, осуществляются по ключу, а в std::set это происходит по самому значению.- В std::map вы можете обновлять значения элементов, используя их ключи. В std::set невозможно обновить значение элемента, поскольку значениями являются сами элементы.Pipes
В C++ пайпы (pipes) представляют собой механизм для односторонней связи между процессами. Они позволяют передавать данные из одного процесса в другой, где один процесс выступает в роли писателя (write end), а другой процесс выступает в роли читателя (read end) пайпа.
Для работы с пайпами вы можете использовать системные вызовы, такие как
Обратите внимание, что дескрипторы чтения и записи пайпа должны быть закрыты в соответствующих процессах с помощью
В C++ пайпы (pipes) представляют собой механизм для односторонней связи между процессами. Они позволяют передавать данные из одного процесса в другой, где один процесс выступает в роли писателя (write end), а другой процесс выступает в роли читателя (read end) пайпа.
Для работы с пайпами вы можете использовать системные вызовы, такие как
pipe, fork и функции чтения/записи (read и write), доступные в POSIX-совместимых операционных системах.Обратите внимание, что дескрипторы чтения и записи пайпа должны быть закрыты в соответствующих процессах с помощью
close, чтобы гарантировать правильное завершение операций чтения и записи.Sockets
Сокеты используются для обмена данными между процессами на разных узлах в сети. Они предоставляют низкоуровневый интерфейс для передачи данных через сетевое соединение.
Для работы с сокетами в C++ вы можете использовать библиотеку сокетов, такую как
Этот код демонстрирует простой обмен данными между сервером и клиентом с использованием сокетов в C++.
Обратите внимание, что в реальной сетевой разработке вам также может понадобиться обработка ошибок, управление соединениями и другие детали. Однако данный пример дает представление о базовых принципах использования сокетов в C++.
Сокеты используются для обмена данными между процессами на разных узлах в сети. Они предоставляют низкоуровневый интерфейс для передачи данных через сетевое соединение.
Для работы с сокетами в C++ вы можете использовать библиотеку сокетов, такую как
BSD Sockets или Boost.Asio.Этот код демонстрирует простой обмен данными между сервером и клиентом с использованием сокетов в C++.
Обратите внимание, что в реальной сетевой разработке вам также может понадобиться обработка ошибок, управление соединениями и другие детали. Однако данный пример дает представление о базовых принципах использования сокетов в C++.
#вопросы_с_собеседований
Можно ли использовать exceptions в конструкторе / деструкторе?
Да, в C++ можно использовать исключения (exceptions) в конструкторе и деструкторе класса. Однако, следует быть внимательным при использовании исключений в этих частях кода и учитывать некоторые особенности.
В конструкторе:
В деструкторе:
Можно ли использовать exceptions в конструкторе / деструкторе?
Да, в C++ можно использовать исключения (exceptions) в конструкторе и деструкторе класса. Однако, следует быть внимательным при использовании исключений в этих частях кода и учитывать некоторые особенности.
В конструкторе:
- Если конструктор выбрасывает исключение, объект не будет полностью сконструирован, и память, выделенная под него, не будет освобождена автоматически. Это может привести к утечке ресурсов или некорректному состоянию программы. В таких случаях следует использовать RAII (Resource Acquisition Is Initialization), чтобы гарантировать правильное освобождение ресурсов при исключениях.- Конструкторы должны быть безопасными в отношении исключений. Если конструктор может выбросить исключение, стоит использовать try-catch в самом конструкторе или передать исключение дальше в коде.В деструкторе:
- Если деструктор выбрасывает исключение, стек будет развернут, и все оставшиеся деструкторы будут вызваны. Однако, при выбрасывании исключения из деструктора, следует быть осторожным, так как это может привести к неопределенному поведению программы.- Деструкторы могут выполнять необходимые операции по очистке ресурсов или уведомлению о состоянии, но исключения следует перехватывать и обрабатывать в другом месте.std::weak_ptr
std::weak_ptr является частью стандартной библиотеки и представляет собой "слабый указатель" на объект, управляемый std::shared_ptr.
Он позволяет получать доступ к объекту, на который ссылается
В этом примере мы создаем два объекта типа
*На втором изображении представлен результат работы кода.
std::weak_ptr является частью стандартной библиотеки и представляет собой "слабый указатель" на объект, управляемый std::shared_ptr.
Он позволяет получать доступ к объекту, на который ссылается
std::shared_ptr, но не влияет на его счётчик ссылок. Такой подход полезен в ситуациях, когда мы хотим избежать возможности утечек памяти из-за циклических ссылок между объектами.В этом примере мы создаем два объекта типа
Node, а затем устанавливаем циклическую ссылку между ними. Если бы мы использовали std::shared_ptr вместо std::weak_ptr для хранения ссылок, объекты node1 и node2 никогда не были бы удалены, поскольку они бы взаимно ссылались друг на друга и счётчики ссылок не достигали бы нуля.*На втором изображении представлен результат работы кода.
#вопросы_с_собеседований
В чем заключается недостаток интерфейса front() + pop_front()?
*Речь идет о недостатке интерфейса
Недостаток интерфейса
Чтобы избежать таких проблем, требуется использовать синхронизацию при одновременном доступе из нескольких потоков. Например, можно использовать мьютекс или другие примитивы синхронизации для защиты контейнера от одновременного доступа.
В чем заключается недостаток интерфейса front() + pop_front()?
*Речь идет о недостатке интерфейса
front() + pop_front() в контексте thread-safe гарантий.Недостаток интерфейса
front() + pop_front() заключается в том, что он оставляет на пользователя ответственность за обеспечение правильной синхронизации при использовании в многопоточной среде. Это может быть источником ошибок, особенно если разработчик забывает или неправильно реализует синхронизацию.Чтобы избежать таких проблем, требуется использовать синхронизацию при одновременном доступе из нескольких потоков. Например, можно использовать мьютекс или другие примитивы синхронизации для защиты контейнера от одновременного доступа.
std::thread
std::thread является частью стандартной библиотеки C++ и предоставляет возможность создания и управления потоками выполнения. Он позволяет запускать функции в отдельных потоках, обеспечивая параллельное выполнение кода.
Обратите внимание, что после создания потока
В приведенном примере мы использовали j
std::thread является частью стандартной библиотеки C++ и предоставляет возможность создания и управления потоками выполнения. Он позволяет запускать функции в отдельных потоках, обеспечивая параллельное выполнение кода.
Обратите внимание, что после создания потока
std::thread, вы должны вызвать join() или detach() для корректной обработки завершения потока. В приведенном примере мы использовали j
oin(), чтобы основной поток дождался завершения потока t1. Если вы вызываете join() после завершения потока, программа может выдать исключение или вызвать неопределенное поведение.#вопросы_с_собеседований
Какие преимущества композиции перед наследованием?
Композиция в c++ позволяет создавать новый класс из более мелких существующих классов, тогда как наследование от других классов позволяет использовать существующие свойства класса.
Основное преимущество композиции заключается в том, что она обеспечивает более гибкую архитектуру и более легкое изменение поведения класса в будущем.
В то время как если использовать наследование при проектировании классов, то это может ограничить возможности изменений в будущем и привести к большему количеству ошибок в программе.
Какие преимущества композиции перед наследованием?
Основное преимущество композиции заключается в том, что она обеспечивает более гибкую архитектуру и более легкое изменение поведения класса в будущем.
В то время как если использовать наследование при проектировании классов, то это может ограничить возможности изменений в будущем и привести к большему количеству ошибок в программе.
template
Ключевое слово template используется в шаблонных функциях и классах для определения обобщённых типов данных, которые могут быть использованы при разработке универсальных алгоритмов.
В этом примере мы определяем шаблонную функцию
Несмотря на то, что
Это означает, что при использовании шаблонов и при неудачной попытке их инстанцирования компилятор не сгенерирует ошибку, а будет искать альтернативные варианты. Использование этой концепции позволяет более гибко управлять перегрузками функций и классов, что может быть особенно полезно при написании библиотек или фреймворков.
Ключевое слово template используется в шаблонных функциях и классах для определения обобщённых типов данных, которые могут быть использованы при разработке универсальных алгоритмов.
В этом примере мы определяем шаблонную функцию
max с типом данных T. Эта функция принимает два аргумента типа T и возвращает значение типа T, которое является максимальным. В вызове функции T будет заменено на фактический тип данных, переданный в качестве параметра шаблона.Несмотря на то, что
template используется для объявления шаблонных классов и функций, он может также применяться для реализации SFINAE. Это означает, что при использовании шаблонов и при неудачной попытке их инстанцирования компилятор не сгенерирует ошибку, а будет искать альтернативные варианты. Использование этой концепции позволяет более гибко управлять перегрузками функций и классов, что может быть особенно полезно при написании библиотек или фреймворков.
#вопросы_с_собеседований
Что случится, если exception выйдет за пределы потока?
Если exception выходит за пределы потока, то оно не может быть обработано на текущем уровне, т. к. он уже завершен. В таком случае исключение будет зарегистрировано как неперехваченное и может привести к аварийному завершению программы.
Чтобы избежать данной ситуации, необходимо обернуть код, где может возникнуть исключение, в try-catch блок на том же уровне, что и поток, с которым он связан.
Что случится, если exception выйдет за пределы потока?
Чтобы избежать данной ситуации, необходимо обернуть код, где может возникнуть исключение, в try-catch блок на том же уровне, что и поток, с которым он связан.
PIMPL (Pointer to Implementation)
PIMPL — это паттерн программирования, который позволяет скрыть внутреннюю реализацию класса от клиента, а также упростить перекомпиляцию кода и улучшить производительность.
Суть PIMPL-паттерна заключается в том, что все данные хранятся в отдельном класс, а в основном хранится только указатель на этот вспомогательный класс, в котором осуществляется вся работа с данными.
В данном примере пользователь класса
PIMPL — это паттерн программирования, который позволяет скрыть внутреннюю реализацию класса от клиента, а также упростить перекомпиляцию кода и улучшить производительность.
Суть PIMPL-паттерна заключается в том, что все данные хранятся в отдельном класс, а в основном хранится только указатель на этот вспомогательный класс, в котором осуществляется вся работа с данными.
В данном примере пользователь класса
MyObject не видит внутреннюю реализацию объекта, что позволяет добавлять/удалять поля без необходимости изменять интерфейс класса. Работа с внутренними данными осуществляется через методы класса Impl, которые вызываются в функциях-членах класса MyObject.#вопросы_с_собеседований
Какие примитивы синхронизации реализованы в C++?
В с++ реализовано множество примитивов синхронизации, ниже представлены их предназначения:
Какие примитивы синхронизации реализованы в C++?
В с++ реализовано множество примитивов синхронизации, ниже представлены их предназначения:
Mutex - используется для блокировки мьютекса при доступе к разделяемому ресурсу.lockguard и uniquelock - используются для автоматической блокировки и разблокировки мьютекса. condition_variable - используется для уведомления потоков о состоянии разделяемого ресурса.atomic - используется для атомарной операции с переменными.semaphore - используется для синхронизации доступа к ограниченному количеству ресурсов.barrier - используется для синхронизации потоков, когда все потоки должны достичь определенной точки их выполнения перед тем, как продолжить работу.