#вопросы_с_собеседований
В чем разница между git fetch и git pull?
Разница между этими командами заключается в том, что когда вы используете команду
А команда
В чем разница между git fetch и git pull?
Разница между этими командами заключается в том, что когда вы используете команду
git fetch, Git извлекает последние изменения из удаленного репозитория в ваш локальный репозиторий, но оставляет эти изменения в отдельной ветке git origin. А команда
git pull извлекает и интегрирует (скачивает и сливает) последние изменения из удаленного репозитория в вашу текущую ветку работы.Семантика перемещения
Семантика перемещения - это концепция, введенная в C++11, которая позволяет компилятору оптимизировать копирование объектов, когда исходный объект не будет использоваться дальше. Это достигается с помощью специальных конструкторов и операторов присваивания, называемых перемещающими конструкторами и перемещающими операторами присваивания.
Перемещение позволяет избежать ненужного копирования ресурсов, таких как динамически выделенная память или файловые дескрипторы, и улучшает производительность программы. Вместо копирования ресурсов, перемещение передает их из одного объекта в другой.
В этом примере мы создаем два вектора строк
Семантика перемещения - это концепция, введенная в C++11, которая позволяет компилятору оптимизировать копирование объектов, когда исходный объект не будет использоваться дальше. Это достигается с помощью специальных конструкторов и операторов присваивания, называемых перемещающими конструкторами и перемещающими операторами присваивания.
Перемещение позволяет избежать ненужного копирования ресурсов, таких как динамически выделенная память или файловые дескрипторы, и улучшает производительность программы. Вместо копирования ресурсов, перемещение передает их из одного объекта в другой.
В этом примере мы создаем два вектора строк
vec1 и vec2. Затем мы используем функцию std::move для передачи содержимого vec1 в vec2 с использованием семантики перемещения. В результате, vec1 становится пустым, а vec2 получает данные, которые раньше были в vec1.anonymous namespaces
Анонимные пространства имен используются для создания области видимости, в которой имена ограничены текущим файлом исходного кода. Это позволяет скрыть реализацию деталей и предотвратить конфликты имен между разными частями кода, особенно когда работаете с большими проектами или совместно с другими разработчиками.
В этом примере переменная
Использование анонимных пространств имен помогает организовать код, уменьшить вероятность конфликтов имен и улучшить инкапсуляцию.
Анонимные пространства имен используются для создания области видимости, в которой имена ограничены текущим файлом исходного кода. Это позволяет скрыть реализацию деталей и предотвратить конфликты имен между разными частями кода, особенно когда работаете с большими проектами или совместно с другими разработчиками.
В этом примере переменная
hidden_variable и функция hidden_function находятся в анонимном пространстве имен. Они будут видимы только в текущем файле исходного кода и не будут доступны из других файлов. Это аналогично объявлению их с static в глобальной области видимости, но анонимные пространства имен являются более современным и предпочтительным подходом.Использование анонимных пространств имен помогает организовать код, уменьшить вероятность конфликтов имен и улучшить инкапсуляцию.
std::atomic_flag::wait
std::atomic_flag::wait - это метод класса std::atomic_flag, который блокирует выполнение потока, пока атомарный флаг не будет равен заданному значению.
В этом примере есть два потока -
Результатом работы данной программы является вывод сообщений "Thread waiting" до изменения
std::atomic_flag::wait - это метод класса std::atomic_flag, который блокирует выполнение потока, пока атомарный флаг не будет равен заданному значению.
В этом примере есть два потока -
t1 и t2, каждый из которых ждет, пока атомарный флаг flag не будет очищен. Когда flag очищается, соответствующий поток переходит в режим выполнения, выводя сообщение "Thread executing".Результатом работы данной программы является вывод сообщений "Thread waiting" до изменения
flag на false и сообщений "Thread executing" после его изменения.#вопросы_с_собеседований
Что такое выравнивание данных?
Выравнивание данных (data alignment) — это процесс выравнивания слов памяти в компьютерной системе таким образом, чтобы каждый адрес начала слова был кратен адресу выравнивания для этого слова. Это делается для увеличения производительности, так как доступ к памяти, выровненной по границе слова, выполняется быстрее, чем к памяти с не выровненным доступом.
Большинство компиляторов C++ пытаются генерировать код, который соответствует некоторым правилам выравнивания памяти на конкретном аппаратном обеспечении.
Что такое выравнивание данных?
Выравнивание данных (data alignment) — это процесс выравнивания слов памяти в компьютерной системе таким образом, чтобы каждый адрес начала слова был кратен адресу выравнивания для этого слова. Это делается для увеличения производительности, так как доступ к памяти, выровненной по границе слова, выполняется быстрее, чем к памяти с не выровненным доступом.
Большинство компиляторов C++ пытаются генерировать код, который соответствует некоторым правилам выравнивания памяти на конкретном аппаратном обеспечении.
#вопросы_с_собеседований
Для чего можно использовать private наследование?
Приватное наследование позволяет производному классу наследовать реализацию базового класса, но делает все его члены (как публичные, так и защищенные) приватными для производного класса.
Приватное наследование может быть полезным в следующих ситуациях:
- Когда мы хотим повторно использовать реализацию базового класса, но не хотим раскрывать его интерфейс для пользователей производного класса.
- Когда мы хотим изменить поведение базового класса, не нарушая инкапсуляцию и сокрытие информации.
- Когда мы хотим использовать базовый класс для управления ресурсами или предоставления служебных функций, которые должны быть скрыты от пользователей производного класса.
Важно отметить, что приватное наследование является менее распространенным, чем публичное наследование, и его использование должно быть обосновано конкретными требованиями дизайна.
Для чего можно использовать private наследование?
Приватное наследование может быть полезным в следующих ситуациях:
-
- Когда мы хотим изменить поведение базового класса, не нарушая инкапсуляцию и сокрытие информации.
- Когда мы хотим использовать базовый класс для управления ресурсами или предоставления служебных функций, которые должны быть скрыты от пользователей производного класса.
Важно отметить, что приватное наследование является менее распространенным, чем публичное наследование, и его использование должно быть обосновано конкретными требованиями дизайна.
mutable
Ключевое слово mutable полезно, когда вам нужно изменять состояние объекта в константном контексте, например, для кеширования результатов или реализации ленивых вычислений. Однако, следует использовать его с осторожностью, чтобы не нарушать принципы инкапсуляции и сокрытия информации.
В этом примере у нас есть класс
В функции
Ключевое слово mutable полезно, когда вам нужно изменять состояние объекта в константном контексте, например, для кеширования результатов или реализации ленивых вычислений. Однако, следует использовать его с осторожностью, чтобы не нарушать принципы инкапсуляции и сокрытия информации.
В этом примере у нас есть класс
Counter с двумя членами: count и mutableCount. Метод increment объявлен как константный — он не должен изменять состояние объекта. Однако, поскольку mutableCount объявлен с ключевым словом mutable, мы можем изменять его значение внутри константного метода increment.В функции
main мы создаем константный объект counter и вызываем метод increment три раза. Значение count остается неизменным, так как его нельзя изменить в константном методе, в то время как значение mutableCount увеличивается на 1 с каждым вызовом метода increment.override
override — это ключевое слово, которое используется для указания на то, что функция в производном классе предназначена для переопределения функции с тем же именем в базовом классе.
Это позволяет достичь полиморфизма на этапе выполнения и предоставить специфическую реализацию функции, которая уже предоставлена в базовом классе.
override — это ключевое слово, которое используется для указания на то, что функция в производном классе предназначена для переопределения функции с тем же именем в базовом классе.
Это позволяет достичь полиморфизма на этапе выполнения и предоставить специфическую реализацию функции, которая уже предоставлена в базовом классе.
Перегрузка функций (overload)
Это возможность определить несколько функций с одним и тем же именем, но с разными параметрами. Компилятор выбирает подходящую функцию на основе количества и типов аргументов, переданных при вызове функции.
Это позволяет использовать одно и то же имя функции для выполнения различных задач, упрощая код и делая его более читаемым.
В этом примере мы определили две перегруженные функции
Это возможность определить несколько функций с одним и тем же именем, но с разными параметрами. Компилятор выбирает подходящую функцию на основе количества и типов аргументов, переданных при вызове функции.
Это позволяет использовать одно и то же имя функции для выполнения различных задач, упрощая код и делая его более читаемым.
В этом примере мы определили две перегруженные функции
add(). Одна из них принимает два целых числа и возвращает их сумму, а другая принимает два числа с плавающей точкой и возвращает их сумму. В функции main() мы вызываем обе функции add() с разными типами аргументов.#вопросы_с_собеседований
Какие есть особенности статических полей класса в языке С++?
Статические поля класса в C++ имеют несколько особенностей:
1. Общий доступ: Статические поля являются общими для всех объектов этого класса. Это означает, что изменение значения статического поля в одном объекте, изменяет его для всех объектов этого класса.
2. Инициализация: Статические поля инициализируются только один раз, когда программа запускается. Значения статических полей сохраняются на протяжении всего времени работы программы.
3. Доступ: Доступ к статическим полям класса возможен без создания объекта этого класса, например, используя имя класса и оператор :: .
4. Память: Статические поля класса хранятся не в куче или стеке, а в статической области памяти, что позволяет им занимать память только один раз, независимо от количества созданных объектов класса.
Какие есть особенности статических полей класса в языке С++?
1. Общий доступ: Статические поля являются общими для всех объектов этого класса. Это означает, что изменение значения статического поля в одном объекте, изменяет его для всех объектов этого класса.
2. Инициализация: Статические поля инициализируются только один раз, когда программа запускается. Значения статических полей сохраняются на протяжении всего времени работы программы.
3. Доступ: Доступ к статическим полям класса возможен без создания объекта этого класса, например, используя имя класса и оператор :: .
4. Память: Статические поля класса хранятся не в куче или стеке, а в статической области памяти, что позволяет им занимать память только один раз, независимо от количества созданных объектов класса.
Вложенные пространства имен (nested namespaces)
Как можно понять из названия, вложенное пространство имен определяется внутри другого пространства имен. Они используются для организации кода, разделения его на логические блоки и предотвращения конфликтов имен.
nested namespaces часто используются в больших проектах, при создании библиотек, а также для версионирования.
Как можно понять из названия, вложенное пространство имен определяется внутри другого пространства имен. Они используются для организации кода, разделения его на логические блоки и предотвращения конфликтов имен.
nested namespaces часто используются в больших проектах, при создании библиотек, а также для версионирования.
const_cast
В этом примере у нас есть класс
Однако, внутри
const_cast — это оператор приведения типов в C++, который используется для изменения квалификаторов const или volatile у указателей или ссылок. Он позволяет временно убрать const или volatile квалификаторы, чтобы изменить значение переменной или вызвать неконстантный метод для константного объекта.В этом примере у нас есть класс
MyClass с двумя методами: nonConstMethod() и constMethod(). Метод nonConstMethod() не является константным, поэтому его нельзя вызвать на константном объекте. Однако, внутри
constMethod() мы используем const_cast для временного изменения квалификатора const у указателя this, что позволяет нам вызвать nonConstMethod() на константном объекте.Const correctness
Когда функция-член класса объявлена с ключевым словом
В этом примере функция
Const correctness — это концепция, которая позволяет явно указывать, может ли функция-член класса изменять объект или нет. Когда функция-член класса объявлена с ключевым словом
const, это означает, что она не может изменять состояние объекта. Если попытаться изменить объект внутри такой функции, компилятор выдаст ошибку.В этом примере функция
age() объявлена как const, что означает, что она не может изменять объект Person. Функция set_age() не объявлена как const, поэтому она может изменять объект.Ленивые вычисления в С++
Ленивые вычисления могут быть реализованы с использованием различных подходов, таких как отложенное вычисление (
В этом примере вычисления выполняются только при первом обращении к числу Фибоначчи с определенным индексом, после чего результат сохраняется в контейнере
lazy evaluation — это стратегия вычислений, при которой вычисления откладываются до тех пор, пока результат не станет действительно необходимым. Это позволяет оптимизировать производительность и ресурсоемкость программы, избегая ненужных вычислений.Ленивые вычисления могут быть реализованы с использованием различных подходов, таких как отложенное вычисление (
deferred evaluation), вычисление по требованию (on-demand evaluation) и мемоизация (memoization).В этом примере вычисления выполняются только при первом обращении к числу Фибоначчи с определенным индексом, после чего результат сохраняется в контейнере
memo для последующего использования. Это позволяет избежать повторных вычислений и оптимизировать производительность программы.Pure virtual function
Чисто виртуальная функция объявляется путем присваивания в объявлении.
В этом примере у нас есть абстрактный базовый класс
Затем мы создаем два производных класса
В функции
Pure virtual function (чисто виртуальная функция) — это виртуальная функция, для которой мы можем иметь реализацию, но мы должны переопределить эту функцию в производном классе, иначе производный класс также станет абстрактным классом. Чисто виртуальная функция объявляется путем присваивания в объявлении.
В этом примере у нас есть абстрактный базовый класс
Shape, который содержит чисто виртуальную функцию draw(). Мы не можем создать объект класса Shape, так как он является абстрактным классом. Затем мы создаем два производных класса
Circle и Rectangle, которые переопределяют функцию draw(). В функции
main() мы создаем объекты circle и rectangle, а также указатель на базовый класс Shape. Мы устанавливаем указатель на объекты circle и rectangle и вызываем функцию draw() для каждого из них.#вопросы_с_собеседований
Как запретить наследовать класс?
Чтобы запретить наследование класса в C++, вы можете объявить класс как
Ключевое слово
Как запретить наследовать класс?
Чтобы запретить наследование класса в C++, вы можете объявить класс как
final. Ключевое слово
final указывает компилятору, что класс не может быть использован в качестве базового класса для других классов. Если попытаться наследовать от класса, объявленного как final, компилятор выдаст ошибку.class Base final {
// ...
};
class Derived : public Base {
// ...
};
// Ошибка компиляции: класс Base объявлен как finalstd::runtime_error
В данном случае, переменная
std::runtime_error является классом исключений в стандартной библиотеке C++, который наследуется от класса std::exception. Этот класс предназначен для представления ошибок, которые обнаруживаются во время выполнения программы. std::runtime_error обычно используется для создания пользовательских исключений, которые могут возникнуть из-за ошибок во время выполнения, таких как некорректные аргументы функции, неправильная работа с памятью или другие ошибки, которые нельзя обнаружить на этапе компиляции.В данном случае, переменная
b равна нулю, поэтому при вызове функции divide будет выброшено исключение. В блоке catch мы перехватываем исключение и выводим сообщение об ошибке.Алгоритм random_shuffle
Он случайным образом переставляет элементы в диапазоне [первый, последний).
Алгоритм меняет значение каждого элемента на какой-либо другой случайно выбранный элемент.
Про различия между
Он случайным образом переставляет элементы в диапазоне [первый, последний).
Алгоритм меняет значение каждого элемента на какой-либо другой случайно выбранный элемент.
Про различия между
shuffle и random_shuffle можно почитать здесь.Ключевое слово friend
В этом примере чтобы предоставить функции
friend в C++ используется для предоставления доступа к закрытым (private) и защищенным (protected) членам класса другим классам или функциям. Это позволяет создавать более гибкие и тесные взаимодействия между классами или функциями, не нарушая инкапсуляцию.friend может применяться к функциям или классам. Если функция объявлена как friend класса, она получает доступ ко всем закрытым и защищенным членам этого класса. Если класс объявлен как friend другого класса, все его методы получают доступ к закрытым и защищенным членам другого класса.В этом примере чтобы предоставить функции
printVolume доступ к закрытым членам класса Box, мы объявляем ее дружественной функцией с помощью ключевого слова friend. Теперь функция printVolume может обращаться к закрытым членам класса Box и вычислять объем коробки.std::atomic
В этом примере у нас есть глобальная переменная
std::atomic является частью библиотеки <atomic>, которая была введена в C++11 для поддержки операций с атомарностью. Атомарные операции гарантируют, что операции будут выполнены как единое, неделимое действие, что особенно важно в многопоточном программировании, чтобы избежать состояний гонки.std::atomic может быть использован в любом месте, где требуется безопасность потоков, например, при обновлении глобальных или общих переменных в многопоточной среде.В этом примере у нас есть глобальная переменная
counter, которую мы хотим инкрементировать в двух разных потоках. Без использования std::atomic мы могли бы столкнуться с состоянием гонки (race condition), когда оба потока пытаются обновить counter одновременно. Однако, поскольку мы используем std::atomic<int>, каждое обновление counter является атомарной операцией, и состояние гонки не происходит.#вопросы_с_собеседований
Что такое cache miss и как это выявить?
Cache miss — это событие, когда система или приложение делает запрос на получение данных из кэша, но эти данные в данный момент отсутствуют в кэш-памяти. В результате системе или приложению приходится делать вторую попытку найти данные, на этот раз в более медленной основной базе данных.
Чтобы выявить cache miss в C++, вы можете использовать инструменты профилирования, которые могут анализировать события, связанные с кэшем. Некоторые из таких инструментов включают:
Что такое cache miss и как это выявить?
Cache miss — это событие, когда система или приложение делает запрос на получение данных из кэша, но эти данные в данный момент отсутствуют в кэш-памяти. В результате системе или приложению приходится делать вторую попытку найти данные, на этот раз в более медленной основной базе данных.
Чтобы выявить cache miss в C++, вы можете использовать инструменты профилирования, которые могут анализировать события, связанные с кэшем. Некоторые из таких инструментов включают:
Cachegrind: инструмент для профилирования кэша, который является частью набора инструментов Valgrind. Cachegrind может анализировать поведение кэша вашего приложения и предоставлять информацию о cache miss и других событиях, связанных с кэшем.Perf: инструмент для профилирования производительности в Linux, который может использовать аппаратные счетчики процессора для анализа событий, связанных с кэшем.OProfile: еще один инструмент для профилирования производительности в Linux, который также может использовать аппаратные счетчики процессора для анализа событий, связанных с кэшем.