Senior C++ Developer
11.7K subscribers
1.47K photos
3 videos
635 links
Изучаем C++.

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

РКН: https://www.gosuslugi.ru/snet/676e9a1e4e740947beca35ba
Download Telegram
Aggregate initialization

Aggregate initialization — это форма инициализации, которая позволяет инициализировать агрегаты (объекты определенных типов) с использованием фигурных скобок и списка значений. Агрегаты могут быть одним из следующих типов:

- Массивы
- Структуры или классы без пользовательских конструкторов, без закрытых или защищенных нестатических членов данных, без базовых классов и без виртуальных функций.

В этом примере мы создаем структуру Point, которая содержит два целочисленных поля x и y. Затем мы инициализируем объект p1 этой структуры с помощью aggregate initialization, указывая значения для x и y в фигурных скобках. Аналогично, мы инициализируем массив arr с помощью списка значений в фигурных скобках.
Uniform initialization

Uniform initialization — это способ инициализации переменных и объектов, который был введен в стандарте C++11. Он представляет собой универсальный и более предсказуемый способ инициализации, который использует фигурные скобки {} вместо круглых () или присваивания =.

Преимущества uniform initialization включают:
- Предотвращает узкое преобразование (narrowing conversion), которое может привести к потере данных.
- Обеспечивает одинаковый синтаксис для инициализации всех типов данных и структур.
- Позволяет инициализировать объекты, которые ранее не могли быть инициализированы, такие как массивы и структуры.

*Важно отметить, что uniform initialization не всегда работает так, как ожидается, особенно в случае с перегруженными конструкторами. В некоторых случаях, компилятор может выбрать не тот конструктор, который вы ожидали, что может привести к неожиданному поведению.
std::any

Это функция C++17, которая предоставляет безопасный с точки зрения типов контейнер для единичных значений любого типа. Она позволяет хранить и манипулировать значениями разных типов в одном объекте, подобно std::variant. Однако, в отличие от std::variant, который требует явного указания допустимых типов, std::any может хранить значения любого типа.

Класс std::any является частью стандартной библиотеки C++ и определяется в заголовке <any>. std::any предоставляет функции, такие как type(), has_value(), reset(), emplace() и другие, которые позволяют манипулировать и запрашивать хранимое значение.

В этом примере мы создаем объект val, который может хранить значения любого типа. Мы присваиваем val различные значения и извлекаем их с помощью std::any_cast и проверки типа с помощью typeid.

Однако при попытке извлечь значение, используя неправильный тип (в данном случае std::any_cast<int>), возникает исключение std::bad_any_cast, которое можно обработать с помощью try-catch.
Получить текущее время и дату в C++

Начиная с C++11, стандартным решением для получения текущего времени и даты в C++ является использование библиотеки chrono.

Мы можем получить текущее время с помощью std::chrono::system_clock::now() от <chrono.h> заголовок и преобразовать его в std::time_t тип (время от эпохи).

Затем преобразовать std::time_t на местное календарное время std::ctime в Www Mmm dd hh:mm:ss yyyy формате, как показано на картинке.
⁉️ malloc — кто же ты на самом деле?

Приглашаем на открытый урок.

🗓 23 июля в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Системное программирование».

Программа урока:
✔️ Как работает malloc и какую роль он играет в управлении памятью в системном программировании;
✔️ Что происходит при выделении памяти: от вызова функции до взаимодействия с ОС и аллокатором;
✔️ Какие типичные ошибки возникают при работе с динамической памятью и к каким последствиям они приводят;
✔️ Как понимать поведение программ на уровне памяти и писать более надежный и предсказуемый код.

После занятия вы будете знать:
- Как устроено динамическое выделение памяти в программах на низком уровне;
- Что именно делает malloc и почему его работа не сводится к "просто выделить память";
- Как более осознанно использовать механизмы управления памятью в системной разработке.

🔗 Ссылка на регистрацию: https://vk.cc/cZyXz5

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
#вопросы_с_собеседований

Что будет выведено на экран?

Объяснение:
В первом случае на печать выведется 9, потому что функция f принимает параметр t = 5, внутри функции к глобальной переменной a прибавляется 5, теперь a = 9, а f возвращает ссылку на неё и печатается значение a, то есть 9).

Далее неважно, что происходит внутри функции, важно, что возвращаемой ссылке на a присваивается 20, значит a = 20. Переменная t не поменяла своё значение, так как в функцию она передается по значению, а не по ссылке.

Затем опять вызываем f(5), при этом a = 20, a = 20 + 5, на печати увидим число 25.

Теперь присваиваем t значение a (в этот момент a = 25 + 5), значит, t станет равно 30.

И, наконец, последняя печать. Вызываем f(30), a = 30 + 30, и возвращается значение 60.
Структуры данных tuple

Так же как и структура данных pair, структура данных tuple (кортеж) представляет собой коллекцию значений разных типов фиксированного размера. Пример на картинке.

Иногда вместо структуры данных tuple удобнее использовать std::array. Эта структура данных похожа на простые массивы, используемые в языке C, снабжённые дополнительными возможностями из стандартной библиотеки C++. Эта структура данных появилась в C++ 11.
Изменяемые лямбда-функции

Применения ключевого слова mutable используется для сохранения состояния в лямбда-функциях. Обычно оператор вызова функции замыкания является константным. Другими словами — лямбда не может модифицировать переменные, захваченные по значению.

Но ключевое слово mutable может быть применено ко всей лямбда-функции, что сделает все её переменные изменяемыми.

Следует заметить, что в отличии от mutable-переменных в объявлении класса, мутабельные лямбда-функции должны использоваться относительно редко и очень аккуратно. Сохранение состояния между вызовами лямбда-функции может быть опасным и контринтуитивным.
Алгоритм fill_n

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

Он принимает начало итератора и количество позиций n в качестве аргументов и заполняет первую позицию n , начиная с позиции, указанной параметром begin , заданным значением.

Синтаксис:
void fill_n (начало итератора, int n, значение типа);
Алгоритм move_backward

Перемещает элементы одного итератора в другой.

Перемещение начинается с последнего элементом в указанном диапазоне и завершается первым элементом в этом диапазоне.
Находим обратный массив в C++

Один из самых быстрых вариантов обратного массива в C++ предполагает использование двух указателей для итерации по массиву. Это обеспечивает линейную сложность O(n) и примерное время выполнения алгоритма равное O(n/2).

Здесь мы создаем две переменные-указатели, start и end, которые начинаются с первого и последнего элемента соответственно. Затем мы проходим по массиву в цикле while, меняя местами элементы и увеличивая указатель start и уменьшая указатель end на каждой итерации.
Подвох с указателями на Default Subobject

Пожалуй, любой С++ разработчик на Unreal Engine имел дело с созданием Default Subobject в конструкторе. Через этот механизм, в частности, создаются компоненты по-умолчанию для акторов. Казалось бы, какие нюансы могут быть связаны с использованием такого стандартного функционала?

Смотреть статью
#вопросы_с_собеседований
Напишите базовую реализацию std::shared_ptr.

std::shared_ptr - умный указатель, который позволяет разделять владение объектом между несколькими shared_ptr. Когда последний shared_ptr уничтожается, он автоматически удаляет объект.
Оператор присваивания ( = ), строго говоря, является бинарным оператором. Его объявление идентично объявлению любого другого бинарного оператора со следующими исключениями:

☑️ Он должен быть нестатической функцией-членом.

☑️ Он не наследуется производными классами.

☑️ Компилятор может создать функцию operator = по умолчанию для типов классов, если она не существует.

В примере показано, как объявить оператор присваивания.
Алгоритм lower_bound

Возвращает итератор, указывающий на первую позицию в отсортированной последовательности, ограниченной диапазоном [first, last), в которую можно вставить значение value, не нарушая упорядоченности.
«Прозрачный промоушн выгоден и разработчику, и его тимлиду». Нюансы карьеры разработчика на С++

https://habr.com/ru/companies/kaspersky/articles/729620/
Узнаем сколько лет человеку по дате его рождения

Для расчета возраста человека по дате его рождения в C++ можно использовать следующий код

В этом коде мы запрашиваем у пользователя его дату рождения, а затем получаем текущую дату с помощью функции time. Затем мы используем структуру tm для извлечения года, месяца и дня из текущей даты и вычисляем количество полных лет с помощью формулы now->tm_year + 1900 - year. Если текущий месяц и день меньше, чем месяц и день рождения, мы уменьшаем возраст на 1. Наконец, мы выводим результат на экран.
➡️ Делегирование конструкторов

В старом C++ вам нужно создавать функцию-член для инициализации и вызывать ее из всех конструкторов для достижения универсально инициализации.

Но начиная с C++11 конструкторы теперь могут вызывать другие конструкторы из того же класса с помощью списка инициализаторов.
Please open Telegram to view this post
VIEW IN TELEGRAM
➡️ Диапазоны и итераторы в C++

В C++ стандартная библиотека шаблонов (STL) предоставляет мощные инструменты для работы с коллекциями данных.

Диапазоны и итераторы позволяют вам легко и эффективно перебирать элементы контейнеров, таких как векторы, списки и множества.

Использование диапазонов и итераторов делает код более чистым и читаемым, упрощает операции перебора и модификации элементов контейнеров.
Please open Telegram to view this post
VIEW IN TELEGRAM
➡️ Удаленные и дефолтные функции

struct demo
{
demo() = default;
};

demo d;


У вас вполне закономерно может возникнуть вопрос, зачем вам писать 8+ букв (т.е. = default;), когда можно просто использовать {}, т.е. пустой конструктор? Никто вас не останавливает. Но подумай о конструкторе копирования, операторе копирования присваиванием, и т.д.

Пустой конструктор копирования, например, не то же самое, что конструктор копирования по умолчанию (который будет выполнять почленную копию всех членов).

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

class demo
{
int m_x;

public:
demo(int x) : m_x(x){};
demo(const demo &) = delete;
demo &operator=(const demo &) = delete;
};

demo obj1{123};
demo obj2 = obj1; // ОШИБКА -- вызов удаленного конструктора копирования
obj2 = obj1; // ОШИБКА -- оператор = удален


🗣️ В старом С++ вы должны были сделать его приватным. Но теперь в вашем распоряжении есть директива компилятора delete.
Please open Telegram to view this post
VIEW IN TELEGRAM
➡️ Концепты (Concepts) в C++

Концепты - это новая возможность в C++20, которая позволяет задавать ограничения на шаблонные параметры. Это позволяет писать более безопасный и читаемый код, поскольку компилятор проверяет соответствие типов требованиям концептов на этапе компиляции.

• template<typename T> concept Arithmetic = std::is_arithmetic_v<T>; определяет концепт Arithmetic, который ограничивает типы, для которых значение std::is_arithmetic_v<T> истинно (т.е. типы, которые являются арифметическими).

• template<Arithmetic T> T add(const T& a, const T& b) определяет шаблонную функцию add, которая будет компилироваться только для типов, удовлетворяющих концепту Arithmetic.
Использование функции add:

Примеры с целыми числами и числами с плавающей запятой успешно вызывают функцию add.

Пример со строками (закомментированный) вызовет ошибку компиляции, так как std::string не является арифметическим типом.
Please open Telegram to view this post
VIEW IN TELEGRAM