C++ Эволюция
2.72K subscribers
296 photos
2 videos
106 links
Обучающий канал по C++
Download Telegram
👩‍💻 ZTG - графический движок для консолей Windows на С++.

Скомпилируйте библиотеку как статическую и включите ее в свой проект, включите файл ZTG.h

#include "ZTG/ZTG.H"

https://github.com/zLouis043/ZTG/
➡️ Модули (Modules) в C++

Модули - это система сборки и организации кода, представленная в C++20.

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

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

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

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

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

C++ Learning 👩‍💻
➡️ Как включить все стандартные библиотеки одной командой

Чтобы разом включить в проект все стандартные библиотеки, используйте #include <bits/stdc++.h>. Это особенно полезно в условиях дефицита времени на соревнованиях по программированию.

Например, вы можете заменить этот фрагмент (и многие другие):

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stack>
#include <set>
#include <queue>
#include <map>


Простой строкой:

#include <bits/stdc++.h>


C++ Learning 👩‍💻
➡️ Злой друг программиста: переопределение ключевых слов

Переопределение ключевых слов — плохая практика программирования, но это возможно через препроцессор. Это может вводить баги, например, #define true false или #define else.

#define int float
#define float char


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

#define public private
#include "mylibrary.h"
#undef private


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

C++ Learning 👩‍💻
Вопрос на собеседовании

Что такое "RAII" (Resource Acquisition Is Initialization) и как это помогает в управлении ресурсами в C++?

Ответ ⬇️
"RAII" — это идиома, при которой инициализация объекта захватывает ресурс, а освобождение ресурса происходит автоматически при уничтожении объекта. Это гарантирует корректное освобождение ресурсов, таких как память или файловые дескрипторы, даже при исключениях.

🗣 Пример:
#include <iostream>

class File {
public:
File(const char* filename) {
file_ = fopen(filename, "w");
if (file_) {
std::cout << "Файл открыт.\n";
}
}

~File() {
if (file_) {
fclose(file_);
std::cout << "Файл закрыт.\n";
}
}

private:
FILE* file_;
};

int main() {
{
File file("example.txt");
// Работа с файлом
} // Файл автоматически закроется при выходе из блока

// Результат выполнения:
// Файл открыт.
// Файл закрыт.
}


C++ Learning 👩‍💻
Вопрос на собеседовании

Как работает RVO (Return Value Optimization) в C++, и в каких случаях оно не применяется?

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

🗣 Пример:
#include <iostream>

struct MyObject {
MyObject() { std::cout << "Создан объект\n"; }
MyObject(const MyObject&) { std::cout << "Скопирован объект\n"; }
MyObject(MyObject&&) { std::cout << "Перемещён объект\n"; }
};

MyObject createObject(bool flag) {
if (flag) {
return MyObject(); // RVO применяется
} else {
MyObject obj;
return obj; // RVO может не применяться
}
}

int main() {
MyObject obj1 = createObject(true);
MyObject obj2 = createObject(false);
}


C++ Learning 👩‍💻
Вопрос на собеседовании

Что такое "SFINAE" (Substitution Failure Is Not An Error) в C++, и как он применяется в шаблонном программировании?

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

Пример использования ⚙️
#include <iostream>
#include <type_traits>

// Шаблон для типов, поддерживающих операцию сложения
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
add(T a, T b) {
return a + b;
}

// Шаблон для других типов (например, строк)
template <typename T>
typename std::enable_if<!std::is_arithmetic<T>::value, void>::type
add(T a, T b) {
std::cout << "Сложение недоступно для этого типа.\n";
}

int main() {
std::cout << add(5, 3) << std::endl; // Сложение чисел
add(std::string("Hello"), std::string("World")); // Строки не поддерживают сложение
return 0;
}

SFINAE позволяет выбирать реализацию функции add() в зависимости от типа аргументов: для числовых типов выполняется сложение, а для других типов выводится сообщение.


C++ Learning 👩‍💻
Вопрос на собеседовании

Что такое rvalue-ссылки в C++ и зачем они нужны?

Ответ ⬇️
Rvalue-ссылки (ссылки на временные объекты) позволяют захватывать и модифицировать временные объекты, избегая ненужного копирования данных. Они обозначаются как T&&. Основное применение rvalue-ссылок — это "перемещение" (move semantics), которое помогает оптимизировать работу с ресурсами. Вместо создания копии и переноса данных, можно использовать rvalue-ссылку и «переместить» содержимое, например, из одного контейнера в другой, обнулив исходный объект.

Пример использования ⚙️
#include <iostream>
#include <vector>

class MyClass {
public:
std::vector<int> data;

MyClass(std::vector<int> d) : data(std::move(d)) {} // перемещающий конструктор

MyClass(MyClass&& other) noexcept : data(std::move(other.data)) {
other.data.clear();
}
};

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
MyClass obj1(std::move(numbers)); // перемещение данных из numbers в obj1

MyClass obj2(std::move(obj1)); // перемещение из obj1 в obj2
std::cout << "Размер obj1 после перемещения: " << obj1.data.size() << std::endl; // Размер obj1 после перемещения: 0
}


C++ Learning 👩‍💻
Вопрос на собеседовании

Что такое перемещение (move semantics) в C++11, как оно работает, и зачем нужен конструктор перемещения?

Ответ ⬇️
Перемещение — это оптимизация, которая позволяет передавать ресурсы (например, память или файлы) из одного объекта в другой без копирования, с помощью конструктора перемещения или оператора перемещения. Это достигается использованием std::move, который превращает объект в rvalue-ссылку, указывающую на временный объект. Конструктор перемещения предотвращает дорогостоящие копирования, делая код более производительным.

Пример использования ⚙️
#include <iostream>
#include <vector>
#include <utility> // Для std::move

class MyVector {
private:
int* data;
size_t size;

public:
// Конструктор
MyVector(size_t n) : size(n), data(new int[n]) {
std::cout << "Конструктор\n";
}

// Конструктор перемещения
MyVector(MyVector&& other) noexcept : size(other.size), data(other.data) {
other.data = nullptr; // Передаем ресурсы и обнуляем указатель у источника
other.size = 0;
std::cout << "Конструктор перемещения\n";
}

// Деструктор
~MyVector() {
delete[] data;
std::cout << "Деструктор\n";
}
};

int main() {
MyVector vec1(10); // Создаем объект
MyVector vec2 = std::move(vec1); // Используем конструктор перемещения

// vec1 больше не владеет ресурсами
return 0;
}

// Результат выполнения:
// Конструктор
// Конструктор перемещения
// Деструктор (vec1, ресурсы уже перенесены)
// Деструктор (vec2)


Если вдруг не поняли, можешь почитать подробное объяснение здесь.

C++ Learning 👩‍💻
Вопрос на собеседовании

Что такое perfect forwarding в C++, как оно работает и зачем оно нужно?

Ответ ⬇️
Perfect forwarding — это техника передачи аргументов в функции или конструкторы так, чтобы сохранить их исходные квалификаторы (например, lvalue, rvalue). Она достигается с помощью универсальных ссылок (T&&) и функции std::forward. Perfect forwarding используется для передачи аргументов в шаблонных функциях без лишних копирований.

Пример использования ⚙️
#include <iostream>
#include <utility>

void process(int& x) {
std::cout << "Lvalue: " << x << "\n";
}

void process(int&& x) {
std::cout << "Rvalue: " << x << "\n";
}

template <typename T>
void forwarder(T&& arg) {
process(std::forward<T>(arg));
}

int main() {
int a = 42;

forwarder(a); // Передаем lvalue
forwarder(100); // Передаем rvalue
return 0;
}


C++ Learning 👩‍💻
Вопрос на собеседовании

Что такое шаблонный метод std::enable_if в C++, как он работает, и в каких случаях его полезно использовать?

Ответ ⬇️
std::enable_if — это шаблонный механизм SFINAE (Substitution Failure Is Not An Error), позволяющий включать или отключать функции или классы на этапе компиляции в зависимости от выполнения условий. Это полезно для создания перегрузок шаблонов или ограничения их использования для определённых типов.

Пример использования ⚙️
#include <iostream>
#include <type_traits>

// Шаблон для целых чисел
template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
printType(T value) {
std::cout << "Целое число: " << value << "\n";
}

// Шаблон для чисел с плавающей точкой
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, void>::type
printType(T value) {
std::cout << "Число с плавающей точкой: " << value << "\n";
}

int main() {
printType(42); // Целое число: 42
printType(3.14); // Число с плавающей точкой: 3.14
// printType("Test"); // Ошибка компиляции: шаблон не подходит
}


C++ Learning 👩‍💻