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
std::piecewise_construct

std::piecewise_construct — это константа типа std::piecewise_construct_t, которая используется для разрешения перегрузок функций, которые принимают два аргумента типа tuple. Она позволяет создавать пары из двух tuple-объектов.

В этом примере мы создаем объект foo, который является парой из строки и вектора целых чисел. Мы передаем константу std::piecewise_construct в качестве первого аргумента конструктора пары, чтобы указать, что мы хотим создать пару из двух tuple-объектов. Затем мы передаем два tuple-объекта в качестве второго и третьего аргументов конструктора пары и выводим значения объекта foo.
std::unique_lock

std::unique_lock — это объект блокировки, который управляет блокировкой мьютекса. Он обеспечивает более гибкое управление блокировкой, чем std::lock_guard, поскольку позволяет заблокировать и разблокировать мьютекс несколько раз.
std::unique_lock использует шаблон RAII (Resource Acquisition Is Initialization), это означает, что при создании объекта std::unique_lock он автоматически блокирует мьютекс, а при уничтожении объекта - автоматически разблокирует его.

В этом примере MyFunction использует std::unique_lock, чтобы заблокировать мьютекс, затем выполняет некоторые операции, разблокирует мьютекс и уведомляет condition. MyOtherFunction также использует std::unique_lock, чтобы заблокировать мьютекс, затем ждет уведомления от MyFunction с помощью метода wait условной переменной condition, и после этого разблокирует мьютекс.

Этот код демонстрирует использование std::unique_lock для синхронизации доступа к общим данным и для взаимодействия между потоками с помощью условных переменных.
std::forward_as_tuple

std::forward_as_tuple — это функция, которая создает кортеж ссылок на аргументы, передаваемые в нее. Этот кортеж подходит для передачи в качестве аргумента в функцию. Кортеж содержит ссылки rvalue, когда в качестве аргументов используются rvalue, и в противном случае содержит ссылки lvalue.

std::forward_as_tuple полезен в тех случаях, когда необходимо передать аргументы функции в виде кортежа ссылок, например при использовании std::map::emplace или std::apply. Он позволяет избежать создания ненужных копий объектов и обеспечивает правильную передачу rvalue и lvalue аргументов.

В этом примере std::forward_as_tuple используется для создания кортежей аргументов для передачи в метод emplace контейнера std::map. Метод emplace принимает пару кортежей, первый из которых содержит аргументы для ключа, а второй — для значения. В этом случае ключ — это число 10, а значение — строка из 20 символов "a".
std::unordered_set

std::unordered_set — это контейнер, который хранит уникальные элементы в неупорядоченном порядке. Он обеспечивает быстрый поиск, вставку и удаление элементов за счет использования хэш-таблицы.

std::unordered_set может быть более эффективным, чем std::set, который использует бинарное дерево поиска для хранения элементов.

В этом примере создается std::unordered_set целых чисел и инициализируется пятью значениями. Затем содержимое множества выводится на экран с помощью цикла for-each. Обратите внимание, что порядок элементов в множестве не соответствует порядку их добавления.

Также в этом примере демонстрируется использование методов bucket_count, begin и end для доступа к отдельным корзинам хэш-таблицы и вывода их содержимого.
std::atomic_thread_fence

std::atomic_thread_fence — это функция, которая устанавливает порядок синхронизации памяти для не атомарных и расслабленных атомарных доступов, как указано в аргументе order, без связанной атомарной операции.

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

В этом примере два потока выполняют функции write_x_then_y и read_y_then_x:

- write_x_then_y устанавливает значение атомарной переменной x равным 1, затем вызывает std::atomic_thread_fence с аргументом std::memory_order_release и устанавливает значение атомарной переменной y равным 1.

- read_y_then_x считывает значение атомарной переменной y, затем вызывает std::atomic_thread_fence с аргументом std::memory_order_acquire и считывает значение атомарной переменной x.
std::map::emplace

std::map::emplace — это функция-член контейнера std::map, которая вставляет новый элемент в контейнер, используя аргументы для конструирования элемента на месте.

Это позволяет избежать ненужных операций копирования или перемещения при тщательном использовании emplace. Если в контейнере уже есть элемент с таким ключом, то новый элемент не будет вставлен.

В этом примере мы создаем std::map с ключами типа std::string и значениями типа int. Затем мы используем emplace для вставки трех пар ключ-значение. В конце мы выводим содержимое map на экран.
std::apply

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

В этом примере мы создаем кортеж args, содержащий два аргумента для функции add. Затем мы используем std::apply для вызова функции add с этими аргументами. В конце мы выводим результат на экран.
std::midpoint

std::midpoint — это функция, которая вычисляет среднюю точку между двумя целыми числами, числами с плавающей точкой или указателями. Она возвращает половину суммы a и b, при этом не происходит переполнения.

Если a и b имеют целочисленный тип и сумма является нечетной, то результат округляется в сторону a. Если a и b имеют тип с плавающей точкой, то происходит не более одной неточной операции.
std::atomic_signal_fence

std::atomic_signal_fence — это функция, которая устанавливает порядок синхронизации памяти для неатомарных и расслабленных атомарных доступов между потоком и обработчиком сигнала, выполняемым в том же потоке. Функция эквивалентна std::atomic_thread_fence, за исключением того, что инструкции процессора для упорядочивания памяти не выполняются.

В этом примере мы используем std::atomic_signal_fence для установления порядка синхронизации памяти между двумя потоками. В конце мы выводим значение переменной b на экран. Результат работы этого кода всегда будет 1.
Дана строка s, найдите длину самой длинной подстроки без повторяющихся символов.

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

Используя правый указатель выполняем итерацию по строке, если текущего символа нет в charSet, то вставляем символ в набор и при необходимости обновляем maxLength. Если символ уже присутствует в наборе, то мы перемещаем левый указатель вперед, удаляя символы из набора, пока повторяющийся символ не исчезнет. Затем вставляем текущий символ в набор и продолжаем итерацию.
В результате возвращаем maxLength как длину самой длинной подстроки без повторяющихся символов.

#разбор_кода
Класс std::string

std::string
— это фундаментальный класс в языке программирования C++, который представляет собой последовательность символов. Он используется для работы со строками и является частью стандартной библиотеки C++.

Рассмотрим пять основных функций std::string:

length() — возвращает длину строки;
append(str) — добавляет строку str в конец текущей строки;
substr(start, length) — возвращает подстроку, начинающуюся с индекса start и имеющую длину length;
find(str) — ищет первое вхождение строки str в текущей строке и возвращает индекс первого символа этой подстроки;
replace(start, length, str) — заменяет подстроку, начинающуюся с индекса start и имеющую длину length, на строку str.

#это_база
Ссылки

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

Символ & используется для обозначения адреса переменной или любой памяти. Переменные, связанные со ссылочными переменными, могут быть доступны как по имени, так и по ссылочной переменной, связанной с ними.

#это_база
Дан целочисленный массив nums, поверните массив вправо на k шагов.

Для решения нам понадобятся два метода:
- Метод reverse принимает вектор чисел и изменяет порядок элементов вектора между индексами.
- Метод rotate принимает вектор чисел и число k, и сдвигает элементы вектора на k позиций вправо.

Этот код выведет на экран результат сдвига элементов вектора {1, 2, 3, 4, 5, 6, 7} на 3 позиции вправо: 5 6 7 1 2 3 4.

#разбор_кода
Перегрузка операторов

Перегрузка операторов позволяет определить для объектов классов встроенные операторы, такие как +, -, * и т. д. Для определения оператора для объектов своего класса, необходимо определить функцию, название которой содержит слово operator и символ перегружаемого оператора.

В этом примере в классе Counter определен оператор сложения, цель которого сложить два объекта Counter. Текущий объект будет представлять левый операнд операции. Объект, который передается в функцию через параметр counter, будет представлять правый операнд операции.

#это_база
Поиск максимальной прибыли

Дан целочисленный массив prices, где prices[i] - это цена данной акции на i-й день. В каждый день вы можете принять решение о покупке и/или продаже акции. В любой момент времени вы можете держать не более одной акции. Однако вы можете купить ее и тут же продать в тот же день. Найдите и верните максимальную прибыль, которую вы можете получить.

Рассмотрим принцип работы maxProfit:

curHold хранит максимальную потенциальную прибыль, если у нас есть акции, а curNotHold - если у нас нет акций.

Для каждой цены алгоритм обновляет значения переменных.
- curHold считается как максимум из двух значений: предыдущего curHold (если мы продолжаем держать акции) и разности между предыдущим curNotHold и текущей ценой на акции (если мы покупаем акции сегодня).
- curNotHold считается как максимум из двух значений: предыдущего curNotHold (если мы продолжаем не покупать акции) и суммы предыдущего curHold и текущей цены на акции (если мы продаем акции сегодня).

#разбор_кода
Итераторы в строках

Итераторы в строках используются для обхода или доступа ко всем символам строки. Для класса string доступны: string::iterator позволяет нам обращаться к строке в прямом направлении слева направо и string::reverse_iterator — в обратном направлении.

В этом примере мы используем оба итератора, чтобы обойти все символы строки. На каждой итерации цикла мы используем оператор разыменования (*it) для доступа к текущему символу строки и выводим его на экран.

Для string::iterator:
- str.begin() возвращает итератор на первый символ строки.
- str.end() возвращает итератор за последний символ строки.

Для string::reverse_iterator:
- str.rbegin() возвращает итератор на последний символ строки.
- str.rend() возвращает итератор перед первым символом строки.

#это_база
std::memory_order_release

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

В этом примере функция producer создает новую строку и сохраняет ее адрес в атомарном указателе ptr, используя std::memory_order_release. Это гарантирует, что все записи в текущем потоке (в данном случае data = 42) будут видны в других потоках, которые приобретают ту же атомарную переменную.

consumer ожидает, пока ptr не будет установлен, используя std::memory_order_acquire. Это гарантирует, что все записи в других потоках, которые освобождают ту же атомарную переменную, будут видны в текущем потоке. После того, как ptr установлен, consumer проверяет значение data, которое было установлено в producer, и утверждает, что оно равно 42.

Результат работы — завершение без ошибок. Оба assert никогда не срабатывают.
#вопросы_с_собеседований
Что такое деструктор?

Деструктор — это экземпляр функции-члена, который вызывается автоматически, если какой-либо объект собирается быть уничтоженным. Используется в основном для освобождения памяти.

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

Они могут быть объявлены как виртуальные или чисто виртуальные, но не как константные, изменчивые, константные изменчивые или статические.
Дано целое число, преобразовать его в римскую цифру.

В нашем решении метод intToRoman принимает целое число в качестве аргумента и возвращает его римское представление в виде строки.

Внутри метода intToRoman создаются четыре массива строк, которые содержат римские числа для единиц, десятков, сотен и тысяч. Затем создается строка Roman, которая формируется путем конкатенации соответствующих элементов из каждого массива, используя арифметические операции для определения индексов.

#разбор_кода
Различия между ссылками и указателями

- Ссылки не могут быть неинициализированными: ссылка всегда должна ссылаться на допустимую переменную, тогда как указатель может быть неинициализированным.

- Ссылки не могут быть переназначены: ссылка должна быть инициализирована при создании и не может быть изменена, чтобы ссылаться на другую переменную. Указатель же может быть переназначен в любое время.

- Ссылки не могут ссылаться на nullptr: ссылка всегда должна ссылаться на допустимую переменную, тогда как указатель может быть установлен в nullptr.

- Ссылки не поддерживают арифметические операции.

- Размер ссылки такой же, как и размер переменной, на которую она ссылается, тогда как размер указателя фиксирован и зависит от архитектуры компьютера.

#это_база
std::memory_order_acquire

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

В этом примере два потока выполняют операции записи и чтения на двух атомарных переменных x и y.
- Операции записи выполняются с std::memory_order_relaxed, что означает, что они не устанавливают никаких ограничений на порядок операций с памятью.
- Операции чтения выполняются с std::memory_order_acquire, что гарантирует, что все записи в других потоках, которые освобождают ту же атомарную переменную, будут видны в текущем потоке после этого вызова load.