Senior C++ Developer
12.6K subscribers
1.33K photos
3 videos
601 links
Изучаем C++.

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

РКН: https://www.gosuslugi.ru/snet/676e9a1e4e740947beca35ba
Download Telegram
Начало работы с Qt

Минимальный исходный код приложения Qt(часть 1).

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

Давайте скомпилируем это приложение. Нажав на зеленую стрелку в левом нижнем углу, Qt Creator скомпилирует и выполнит его.

И что случилось? Приложение как бы запущено и не отвечает. Это на самом деле нормально. Цикл событий работает и ожидает событий, таких как щелчки мышью в графическом интерфейсе, но мы не предоставили никаких событий для обработки, поэтому он будет выполняться бесконечно.

Давайте добавим что-то для отображения(часть 2). Скомпилируйте его и… вот оно! Наше первое окно!
60 антипаттернов для С++ программиста

Смотреть статью
Пример оконного приложения на C++ Qt

В программе окно создается на основе библиотечного класса QFrame. Этот класс является потомком класса QWidget. Так что можно без всяких проблем заменить в программе QFrame на QWidget.

Подробнее можно почитать здесь.
#вопросы_с_собеседований
Как работает оператор new в C++ и почему используется именно этот оператор для выделения динамической памяти?

Оператор new используется в C++ для выделения динамической памяти (heap memory), которая выделяется во время выполнения программы. При его вызове, сначала выделяется необходимое количество памяти из операционной системы, а затем возвращается указатель на эту область памяти.

При исполнении оператора new происходит следующее:
1. Сначала он выделяет память в размере, указанном в аргументе оператора или размере типа данных, на который указывает указатель.
2. Затем он вызывает конструктор для создания объекта в выделенной области памяти.
3. Возвращает указатель на выделенную память.

Оператор new является предпочтительным для выделения памяти по сравнению с функцией malloc в C, поскольку он позволяет при выделении памяти автоматически вызывать конструкторы объектов. С использованием оператора new не нужно явно выделять память под объекты и вызывать конструкторы отдельно.

В данном примере оператор new выделяет память под объект класса MyClass и вызывает его конструктор. Оператор delete используется для освобождения ранее выделенной памяти.
#вопросы_с_собеседований
Предполагая, что buf является валидным указателем, в чем проблема в приведенном на картинке коде? Каким был бы альтернативный способ реализации этого, который позволил бы избежать этой проблемы?

Проблема в коде заключается в том, что --sz >= 0 всегда будет истинным, поэтому вы никогда не выйдете из цикла while (поэтому вы, вероятно, в конечном итоге испортите память или вызовете какое-то нарушение памяти или какой-либо другой программный сбой, в зависимости от того, что вы делаете внутри цикла). Причина, по которой --sz >= 0 всегда будет истинной, заключается в том, что тип sz равен size_t. size_t на самом деле просто псевдоним одного из основных беззнаковых целочисленных типов. Следовательно, поскольку sz не имеет знака, оно никогда не может быть меньше нуля (поэтому условие никогда не может быть ложным). Одним из примеров альтернативной реализации, позволяющей избежать этой проблемы, может быть использование цикла for следующим образом:
for (size_t i = 0; i < sz; i++)
Ключевое слово requires

Ключевое слово requires используется в контексте концепций (concepts) для определения требований, которые тип должен удовлетворять. Концепции представляют собой инструмент в C++, введенный в стандарте C++20, который позволяет более точно указывать ограничения на типы данных, которые могут использоваться в шаблонах.

В примере на картинке Sortable — это концепция, описывающая типы, для которых определены операторы сравнения («<» и «>»). Функция sortAndPrint принимает два аргумента типа T, удовлетворяющего концепции Sortable, и сравнивает их.

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

#для_начинающих
std::weak_ordering

std::weak_ordering — это тип в C++, который введен в стандарте C++20 для использования в контексте трехсторонних операторов сравнения (таких как операторы <=> и ==). Этот тип предоставляет четыре значения: std::weak_ordering::equivalent, std::weak_ordering::less, std::weak_ordering::greater и std::weak_ordering::unordered.

std::weak_ordering используется для сравнения объектов, когда сравнение может быть неоднозначным или невозможным, но при этом необходимо учесть отношение порядка. Например, при сравнении чисел с плавающей точкой, если одно или оба числа являются NaN (Not a Number), то результат сравнения может быть неопределенным. В таких случаях std::weak_ordering может использоваться для предоставления информации о том, являются ли объекты эквивалентными, меньшими, большими или не сравнимыми.

#для_продвинутых
std::apply

std::apply
— это функция, введенная в стандарте C++17, которая предоставляет возможность применения кортежа (или пары) в качестве аргументов функции. Это удобный способ передачи элементов кортежа в функцию, которая принимает переменное количество аргументов.

#для_начинающих
В чем разница между статической и динамической библиотеками?

Статические и динамические библиотеки — это два основных типа библиотек, используемых в программировании на C++ (и в других языках программирования).

Статические библиотеки:
— Имеют расширение ".lib" (на платформе Windows) или ".a" (на платформах, таких как Linux).
— Код из статических библиотек копируется в исполняемый файл (или в другую статическую библиотеку) в момент компиляции. Это означает, что код библиотеки становится частью исполняемого файла.
Преимущества: Приложение не зависит от внешних библиотек во время выполнения, что делает его более портативным и проще в распространении.
Недостатки: Увеличивает размер исполняемого файла, и любые изменения в коде библиотеки требуют повторной компиляции всего приложения.

Динамические библиотеки:
— Имеют расширение ".dll" (на платформе Windows) или ".so" (на платформах, таких как Linux).
— Код из динамической библиотеки загружается в память во время выполнения программы. Это означает, что библиотека остается внешней и может быть загружена и выгружена во время выполнения.
Преимущества: Экономия памяти, так как код библиотеки не дублируется в каждом исполняемом файле. Легче обновлять библиотеки без перекомпиляции всего приложения.
Недостатки: Приложение зависит от наличия соответствующих динамических библиотек в системе во время выполнения. Требуется управление версиями и обработка конфликтов.
std::find_if

std::find_if — это стандартный алгоритм, предоставляемый библиотекой <algorithm>. Этот алгоритм предназначен для поиска первого элемента в заданном диапазоне, который удовлетворяет заданному условию, определенному предикатом.

Вот общий формат std::find_if:

#include <algorithm>

template<class InputIt, class UnaryPredicate>
InputIt find_if(InputIt first, InputIt last, UnaryPredicate p);


first и last представляют диапазон элементов для поиска. first указывает на начало диапазона, а last указывает за его пределы.
p — это унарный предикат, то есть функция, принимающая один аргумент и возвращающая true, если элемент удовлетворяет условию, и false в противном случае.

#для_начинающих
Создайте класс Rectangle с двумя закрытыми членами данных для длины и ширины. Добавьте конструктор по умолчанию, конструктор с параметрами и методы для расчета площади и периметра прямоугольника. Затем напишите функцию main, в которой создается объект класса Rectangle, используя динамическое выделение памяти, и выводятся площадь и периметр прямоугольника.

1) Класс Rectangle: Класс имеет два закрытых члена для длины и ширины. Он включает в себя конструктор по умолчанию и конструктор с параметрами.
2) Методы area и perimeter: Эти методы вычисляют площадь и периметр прямоугольника соответственно.

3) Динамическое Выделение Памяти: В функции main создается объект rect класса Rectangle с использованием оператора new. Это позволяет объекту сохранять свое состояние во время выполнения программы до явного освобождения памяти.
4) Вывод и Освобождение Памяти: Выводятся площадь и периметр, после чего освобождается память, выделенная для rect, с помощью оператора delete.


Этот вопрос тестирует понимание объектно-ориентированного программирования, работы с динамической памятью и основных концепций C++.
Функция wcspbrk

Функция wcspbrk является частью стандартной библиотеки C++ и предназначена для поиска первого вхождения одного из символов из заданного набора символов в строке, представленной в формате wide character (широкие символы, представленные типом данных wchar_t). Эта функция аналогична функции wspbrk из стандартной библиотеки C.

Прототип функции wcspbrk выглядит следующим образом:

const wchar_t* wcspbrk(const wchar_t* str, const wchar_t* charset);

str — указатель на строку типа wchar_t, в которой будет выполняться поиск.
charset — указатель на набор символов типа wchar_t, которые нужно найти в строке str.
Функция wcspbrk возвращает указатель на первое вхождение любого символа из charset в строке str, или NULL, если ни один символ из charset не найден в строке.

#для_продвинутых
Функции Бесселя

Функции Бесселя в С++ представляют собой набор математических функций, которые используются для решения различных задач, связанных с волновой оптикой, акустикой, механикой и другими областями физики и инженерии. Они названы в честь немецкого математика Фридриха Бесселя.

В С++ функции Бесселя можно использовать, включив заголовочный файл <cmath>. Стандартная библиотека С++ предоставляет следующие функции Бесселя:

j0, j1, jn: Эти функции вычисляют функции Бесселя первого рода Jn(x) для заданных значениях x и целых индексов n.
y0, y1, yn: Эти функции вычисляют функции Бесселя второго рода (также известные как функции Неймана) Yn(x) для заданных значений x и целых индексов n.
I0, I1, In: Эти функции вычисляют модифицированные функции Бесселя первого рода In(x) для заданных значений x и целых индексов n.
K0, K1, Kn: Эти функции вычисляют модифицированные функции Бесселя второго рода Kn(x) для заданных значений x и целых индексов n.

#для_продвинутых
sync_file_range()

Вызов sync_file_range() позволяет точно контролировать синхронизацию открытого файла, задаваемого файловым дескриптором fd, с диском.

В offset задаётся начальный байт диапазона файла, который нужно синхронизировать. В nbytes указывается длина синхронизируемого диапазона (в байтах); если nbytes равно нулю, то синхронизируются все байты, начиная с offset и до конца файла. Синхронизация выполняется в единицах размера системной страницы: значение offset округляется к меньшей границе страницы; (offset+nbytes-1) округляется к большей границе страницы.

Данный системный вызов очень опасен и не должен использоваться в переносимых программах. Ни одна из этих операций перезаписи не касается метаданных файла. Поэтому, если приложение строго не выполняет перезаписи уже выделенных дисковых блоков, то нет никаких гарантий, что данные будут будьте доступны после катастрофического отказа.

#для_продвинутых
equal_range

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

Прототип функции equal_range выглядит следующим образом:

std::pair<iterator, iterator> equal_range(const Key& key);

Где:
iterator — тип итератора контейнера.
Key — значение, для которого нужно найти диапазон.

#для_продвинутых
SFML

SFML (Simple and Fast Multimedia Library) — это библиотека, предназначенная для разработки мультимедийных приложений, включая 2D и 3D игры, аудио и видео. Она предоставляет доступ к различным мультимедийным ресурсам и упрощает работу с графикой, аудио, сетью и вводом.

Вот основные шаги для использования SFML в C++:

1. Сначала установите библиотеку SFML на вашем компьютере. Вы можете скачать библиотеку с официального сайта SFML и следовать инструкциям по установке для вашей операционной системы.
2. Создайте новый проект C++ в вашей среде разработки (например, Visual Studio, Code::Blocks, CLion и др.).
3. Вам нужно убедиться, что ваш проект настроен для использования SFML. Для этого укажите пути к заголовочным файлам и библиотекам SFML в настройках проекта.
4. Ваш код будет включать заголовочные файлы SFML и вызов функций для работы с графикой, аудио и другими мультимедийными ресурсами.
5. Скомпилируйте свой проект с учетом настроек SFML, и запустите его.

#для_продвинутых
Специализация шаблонов

Специализация шаблонов (template specialization) позволяет предоставить особое определение (или реализацию) шаблона для конкретного типа данных или набора типов данных. Это позволяет адаптировать поведение шаблона для специфических сценариев, когда общее определение шаблона не подходит.

Специализации шаблонов позволяют создавать более точную и оптимизированную логику для определенных типов данных или сценариев использования. При компиляции компилятор выбирает наиболее подходящую специализацию на основе переданных типов или аргументов шаблона.

Обратите внимание, что специализация шаблонов может быть мощным инструментом, но её следует использовать осторожно, так как неправильное использование может привести к сложностям при поддержке кода и его понимании.

#для_продвинутых
Boost.Serialization

Boost.Serialization — это часть библиотеки Boost, которая позволяет сериализовать и десериализовать объекты C++ для передачи их между разными программами или для сохранения их состояния в файле.

Напоминаем: Сериализация — это процесс преобразования объектов C++ в последовательность байтов, которые могут быть записаны в файл или переданы через сеть. Десериализация — это процесс обратного преобразования последовательности байтов обратно в объекты C++.

#для_продвинутых
Метапрограммирование шаблонов

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

Важно помнить, что метапрограммирование шаблонов может быть сложным и приводить к сложноотлавливаемым ошибкам компиляции. Эта техника часто используется в библиотеках стандартной библиотеки C++, таких как STL (Standard Template Library), для создания обобщенных и эффективных алгоритмов и контейнеров.

#для_продвинутых