Senior C++ Developer – Telegram
Senior C++ Developer
12.3K subscribers
1.36K photos
3 videos
609 links
Изучаем C++.

По вопросам сотрудничества: @adv_and_pr

РКН: https://www.gosuslugi.ru/snet/676e9a1e4e740947beca35ba
Download Telegram
#вопросы_с_собеседований
Что такое internal linkage?

internal linkage (внутреннее связывание) означает, что имя (например, переменная или функция) видимо и доступно только в пределах файла (или, точнее, в пределах трансляционной единицы), в котором оно определено. Это означает, что если у вас есть два разных файла с исходным кодом, и в каждом из них определено имя с внутренней связью, то эти два имени считаются разными и не конфликтуют друг с другом.

Внутреннюю связь в C++ можно установить несколькими способами. Например, если вы определите переменную или функцию как static, она будет иметь внутреннюю связь. Также, имена в безымянных пространствах имен (anonymous namespaces) имеют внутреннюю связь.
Флаг компиляции -fPIC

-fPIC используется для генерации позиционно-независимого кода (Position Independent Code, PIC).
Это означает, что сгенерированный код может быть исполнен независимо от его абсолютного адреса в памяти.

Это особенно полезно при создании динамических библиотек, которые могут быть загружены в произвольное место в памяти во время выполнения.

Результатом применения этого флага будет объектный файл, который содержит позиционно-независимый код. Этот объектный файл затем может быть использован для создания динамической библиотеки, которую можно загрузить и использовать во время выполнения других программ.
Синхронизация между стандартными потоками C++ и C

Функция std::ios::sync_with_stdio используется для установки синхронизации между стандартными потоками C++ и стандартными потоками C.

По умолчанию, эта синхронизация включена, это означает, что потоки C++ и C могут быть использованы вместе, и их буферы будут иметь правильный порядок.
Вызов std::ios::sync_with_stdio(false) может увеличить производительность ввода/вывода, но после этого стандартные потоки C++ и C не должны использоваться вместе.

Этот код используется для быстрого чтения и записи данных, что особенно полезно в соревновательном программировании.

Здесь мы также отвязываем std::cin от std::cout, что дополнительно увеличивает скорость ввода/вывода и используем \n вместо std::endl, т. к. std::endl выполняет отчиску буфера и может замедлить вывод.
Заполняем вектор последовательными значениями

С этим нам поможет функция std::iota, которая является частью библиотеки <numeric>. Она используется для заполнения диапазона последовательными значениями, начиная с определенного значения.

В этом примере мы создаем вектор из 10 элементов, заполняем его значениями от 1 до 10 с помощью std::iota и выводим вектор.
#вопросы_с_собеседований
Можно ли выбрасывать exception из конструктора? Какие поля будут сконструированы, какие поля будут разрушены?

в C++ выбрасывать исключения из конструктора можно. Это обычно делается, когда в процессе инициализации объекта происходит ошибка, и объект не может быть корректно сконструирован.

Если исключение выбрасывается из конструктора, то все поля, которые были успешно сконструированы до момента выброса исключения, будут корректно разрушены. Это гарантируется механизмом исключений в C++.

Важно помнить, что только те поля, которые были успешно сконструированы, будут разрушены. Если исключение выбрасывается в процессе конструирования поля, то это поле не будет разрушено, так как его конструктор не был успешно завершен.
Глубокое копирование

Термин глубокое копирование подразумевает создание нового объекта и копирование всех значений полей исходного объекта в новый объект. Если поле является указателем, то вместо копирования самого указателя создается новый объект, на который указывает исходный указатель, и новый указатель на этот новый объект сохраняется в новом объекте.

Это отличается от поверхностного копирования, при котором копируются только значения полей, включая указатели, но не объекты, на которые они указывают.

В этом примере у нас есть класс Deep, который содержит указатель data. В копирующем конструкторе мы создаем новый объект Deep, копируя значение, на которое указывает data в исходном объекте, а не сам указатель.
В функции main мы создаем объект obj1 и затем создаем obj2, используя копирующий конструктор. Затем мы меняем значение, на которое указывает data в obj2, и это не влияет на obj1, что подтверждает, что было выполнено глубокое копирование.
std::tie

std::tie — это функция, которая создает кортеж ссылок на lvalue из своих аргументов или экземпляров std::ignore.

Она может использоваться для распаковки кортежей или пары значений в отдельные переменные. Например, если у вас есть функция, которая возвращает std::pair или std::tuple, вы можете использовать std::tie, чтобы присвоить значения этого кортежа отдельным переменным.

В этом примере мы используем std::tie для распаковки результата вызова set_of_s.insert(value) в две переменные: итератор iter и логическую переменную inserted.
Это позволяет нам проверить, было ли значение успешно вставлено в набор.
constinit

constinit — это новый ключевое слово и спецификатор в C++20. Он используется для объявления переменных со статическим или потоковым временем хранения. Если переменная объявлена с constinit, ее инициализирующее объявление должно быть выполнено с constinit.
Если переменная, объявленная с constinit, имеет динамическую инициализацию (даже если она выполняется как статическая инициализация), программа является некорректной.

constinit гарантирует, что переменная инициализируется на этапе компиляции, и что статическая инициализация не может привести к проблемам с порядком инициализации. Однако он не делает переменную неизменяемой и не подразумевает const или constexpr. Однако constexpr подразумевает constinit.
Переменная может быть одновременно const и constinit, но не может быть одновременно constexpr и constinit.
#вопросы_с_собеседований
Мьютекс и Семафор: Какой из них вы бы использовали для защиты доступа к операции приращения и почему?

Мьютекс и семафор — это два разных механизма синхронизации. Мьютекс используется для обеспечения взаимного исключения доступа к общим ресурсам, в то время как семафор используется для управления доступом к ограниченному числу ресурсов.

В случае операции приращения, которая должна быть выполнена атомарно, стоит использовать мьютекс. Он гарантирует, что только один поток может получить доступ к общему ресурсу в определенный момент времени. Это предотвращает состояние гонки и обеспечивает корректность работы программы.
using enum

Конструкция using enum была добавлена в C++20 и позволяет импортировать и использовать имена элементов перечисления без указания имени перечисления.
Это удобно, когда вы хотите использовать перечисление внутри класса или функции без необходимости указывать полное имя перечисления.

using enum также может использоваться в объявлениях классов для добавления элементов перечисления из именованного перечисления в область видимости класса.
Форматирование текста в С++20

std::format — это функция форматирования текста, которая появилась в C++20. Она предлагает безопасную и расширяемую альтернативу семейству функций printf. Эта функция предназначена для дополнения существующей библиотеки C++ I/O streams.

В этом примере мы используем std::format для форматирования строки "Hello, {}!", где {} является заполнителем для аргумента "world". Результатом работы этого кода будет строка "Hello, world!", которая выводится на экран с помощью std::cout.
std::stringstream

std::stringstream — это класс, который позволяет выполнять операции ввода-вывода на строковых потоках. Он эффективно хранит экземпляр std::basic_string и выполняет операции ввода-вывода на нем.

В этом примере мы создаем std::stringstream из строки "10 20 30". Затем мы извлекаем три целых числа из потока с помощью оператора >> и сохраняем их в переменных x, y и z. Результатом работы этого кода будет вывод на экран чисел 10, 20 и 30.
decltype

decltype — это ключевое слово, используемое для запроса типа выражения. Оно было введено в C++11 и используется в основном в обобщенном программировании, где часто трудно или даже невозможно определить тип выражения.

Один из примеров использования decltype — это объявление шаблонной функции, тип возвращаемого значения которой зависит от типов аргументов шаблона.

В C++11 можно использовать decltype для конечного возвращаемого типа вместе с ключевым словом auto, чтобы объявить шаблонную функцию, возвращаемый тип которой зависит от типов аргументов шаблона.

В этом примере кода показано, как decltype используется для определения типа выражения. Результат работы этого кода будет зависеть от того, какие значения будут присвоены переменным и какие функции будут вызваны.
atoll

Функция atoll в языке программирования C++ является функцией библиотеки заголовка cstdlib. Она используется для преобразования строки в значение типа long long int.

В этом примере кода мы считываем строку с помощью функции fgets, а затем преобразуем ее в значение типа long long int с помощью функции atoll. Затем мы выводим полученное значение и его удвоенное значение.
Результат работы этого кода будет зависеть от того, какое значение будет введено пользователем.
forward_list

forward_list — это контейнер, который поддерживает быструю вставку и удаление элементов из любого места. forward_list реализован в виде односвязного списка, который хранит только ссылку на следующий элемент.

Добавление, удаление и перемещение элементов внутри списка или между несколькими списками не инвалидирует итераторы, которые в настоящее время ссылаются на другие элементы в списке. Однако итератор или ссылка, ссылающиеся на элемент, инвалидируются, когда соответствующий элемент удаляется (через erase_after) из списка.

В этом примере мы создаем forward_list с именем numbers, с помощью метода front() получаем первый элемент списка и выводим его на экран. Далее мы перебираем все элементы списка с помощью цикла for и выводим их на экран.
std::make_unique

std::make_unique — это функция шаблона, которая создает и возвращает std::unique_ptr, который управляет новым объектом типа T, созданным с помощью переданных аргументов.

std::make_unique может быть полезен в задачах, где требуется управление динамически выделенной памятью с помощью std::unique_ptr. Она обеспечивает безопасность исключений и удобство использования по сравнению с явным использованием new и delete.

В этом примере мы используем std::make_unique для создания std::unique_ptr, который управляет новым объектом типа Foo. Мы передаем аргумент 5 в конструктор Foo, чтобы инициализировать поле x этим значением. Затем мы используем оператор -> для доступа к полю x и выводим его значение на экран.
std::initializer_list

std::initializer_list — это легковесный прокси-объект, который предоставляет доступ к массиву объектов типа
const T.
Объект std::initializer_list автоматически создается, когда используется список инициализации в фигурных скобках для инициализации объекта, где соответствующий конструктор принимает параметр std::initializer_list.

Список инициализации в фигурных скобках используется как правый операнд присваивания или как аргумент функции, и соответствующий оператор присваивания/функция принимает параметр std::initializer_list. Список инициализации в фигурных скобках связывается с auto, включая цикл for с диапазоном 1.
std::bitset

std::bitset — это шаблон класса, который представляет собой последовательность битов фиксированного размера N. Битовые множества могут управляться стандартными логическими операторами и преобразовываться в строки и целые числа.

В этом примере мы создаем битовое множество b размером 8 бит и инициализируем его значением 42. Затем мы выводим его на экран. Результат работы этого кода: 00101010.
#вопросы_с_собеседований
Почему стоит использовать std::swap вместо прямого обмена значений?

Использование std::swap вместо прямого обмена значений может быть более эффективным, так как std::swap может быть специализирован для определенных типов данных.
Это означает, что для некоторых типов данных может существовать более эффективная реализация std::swap, которая будет использоваться вместо общей реализации.

Также использование std::swap улучшает читаемость кода и делает его более ясным для других разработчиков.
метод Mutator

Метод Mutator, также известный как метод Setter, используется для управления изменениями переменной. Он позволяет изменять значение закрытой переменной класса через публичный метод, который принимает желаемое новое значение в качестве параметра, опционально проверяет его и изменяет закрытую переменную.

Mutator может использоваться для решения различных задач, например, для проверки входных данных или для выполнения дополнительных действий при изменении значения переменной.

В этом примере Customer имеет закрытую переменную m_age, которая представляет возраст клиента. setAge является методом Mutator для этой переменной.
Он принимает новое значение в качестве параметра и проверяет, что оно неотрицательное, прежде чем изменить значение m_age. В функции main создается объект Customer и вызывается setAge для установки значения возраста.

Результатом работы этого кода будет создание объекта класса Customer с установленным значением возраста равным 25.
memmove

Функция memmove используется для копирования блока памяти из одного места в другое. Она объявлена в заголовочном файле <cstring>. Она принимает аргументы типа void * и const void *, что позволяет ей работать с любыми типами данных. Она просто копирует указанное количество байтов из исходного буфера в целевой.

memmove может обрабатывать перекрывающиеся буферы. В отличие от memcpy, которая просто копирует данные из одного места в другое, memmove может безопасно перемещать данные, даже если исходный и целевой буферы перекрываются.

Функция memmove может быть полезна для удаления элементов из массива. Например, если вы хотите удалить элемент из массива и сдвинуть оставшиеся элементы влево, вы можете использовать memmove для перемещения данных в массиве.