Почему std::optional<T> часто понимают неправильно?
Потому что
То есть если значение есть, объект
Например:
здесь
Из-за этого у optional другая семантика:
Поэтому
Но если тебе нужна именно не-владеющая ссылка на уже существующий объект,
🔥
📣 C++ Ready | #совет
Потому что
optional выглядит как “объект, которого может не быть”, и из-за этого его легко мысленно приравнять к указателю. Но это другая модель.std::optional<T> хранит значение внутри себя.То есть если значение есть, объект
T находится прямо внутри optional, а не где-то отдельно в памяти.Например:
std::optional<std::string> name = "Gus";
здесь
optional не указывает на строку — он содержит строку внутри себя.Из-за этого у optional другая семантика:
• копирование optional копирует и само значение
• перемещение optional перемещает значение
• optional не подходит как замена ссылке
• отсутствие значения — это отдельное состояние самого объекта, а не nullptr
Поэтому
optional удобен, когда функция может вернуть значение или не вернуть ничего:std::optional<User> find_user(int id);
Но если тебе нужна именно не-владеющая ссылка на уже существующий объект,
optional для этого обычно не лучший инструмент.std::optional<T> — это контейнер для “значение есть или его нет”, а не просто красивый указатель.Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍4🔥3
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥6👍4
This media is not supported in your browser
VIEW IN TELEGRAM
В этом репозитории собраны десятки книг по разным языкам и направлениям, таким как C/C++ и многое другое. Всё разложено по категориям, поэтому можно быстро найти нужную тему. Здесь есть как базовые учебники по синтаксису и указателям, так и более серьёзные материалы по памяти, низкоуровневой работе и системному программированию.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤7🤝6
Удаление элементов без erase-remove идиомы: `std::erase_if`
Когда нужно удалить элементы из контейнера по условию, в старом C++ часто использовали связку
В C++20 для этого есть
Например, удалим все отрицательные значения из
После этого в контейнере останутся только положительные значения:
Без
Новая версия лучше показывает намерение: мы не “переставляем элементы и потом стираем хвост”, а просто удаляем всё, что подходит под условие.
Так можно аккуратно чистить контейнеры без ручных циклов и лишнего служебного кода.
🔥
📣 C++ Ready | #практика
Когда нужно удалить элементы из контейнера по условию, в старом C++ часто использовали связку
std::remove_if + erase. Работает, но выглядит шумно и не сразу читается.В C++20 для этого есть
std::erase_if.Например, удалим все отрицательные значения из
std::vector:std::vector<int> values{3, -1, 7, -5, 10};
std::erase_if(values, [](int x) {
return x < 0;
});После этого в контейнере останутся только положительные значения:
for (int x : values) {
std::cout << x << ' ';
}
// 3 7 10Без
std::erase_if пришлось бы писать длиннее:values.erase(
std::remove_if(values.begin(), values.end(), [](int x) {
return x < 0;
}),
values.end()
);
Новая версия лучше показывает намерение: мы не “переставляем элементы и потом стираем хвост”, а просто удаляем всё, что подходит под условие.
std::erase_if работает не только с std::vector, но и с другими стандартными контейнерами:std::map<std::string, int> counters{
{"ok", 10},
{"errors", 0},
{"warnings", 3}
};
std::erase_if(counters, [](const auto& item) {
return item.second == 0;
});Так можно аккуратно чистить контейнеры без ручных циклов и лишнего служебного кода.
std::erase_if делает удаление по условию коротким и читаемым: одно действие — одна понятная строка.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥5❤3
Например, Indexing ускоряет поиск по таблицам, а Sharding помогает разделить большие объёмы данных между несколькими узлами.
На картинке — 7 стратегий масштабирования БД: индексы, materialized views, denormalization, vertical scaling, caching, replication и sharding.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥6❤5🤝1
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18❤5👍3👎1🤝1
В этой статье:
• как устроена базовая камера и выпуск лучей в сцену
• как найти пересечение луча со сферой и рассчитать цвет пикселя
• как добавить материалы, отражения, тени и получить объёмную картинку🔊 Продолжай читать на habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍7🤝3
Почему
Потому что
В таком контексте это forwarding reference, которая может принять и временный объект, и обычную lvalue-переменную.
Например:
Здесь в
Но внутри функции мы пишем:
И этим насильно превращаем
В итоге
То есть проблема не в самом
Для perfect forwarding нужно использовать:
• lvalue остается lvalue
• rvalue остается rvalue
А
🔥 В forwarding-коде
📣 C++ Ready | #совет
std::move внутри forwarding-функции может быть ошибкой?Потому что
T&& в шаблоне — это не всегда rvalue-ссылка.В таком контексте это forwarding reference, которая может принять и временный объект, и обычную lvalue-переменную.
Например:
std::string s = "hello";
wrapper(s);
Здесь в
wrapper передается lvalue.Но внутри функции мы пишем:
process(std::move(value));
И этим насильно превращаем
value в rvalue.В итоге
process() может переместить данные из объекта s, хотя вызывающий код передавал обычную переменную и не ожидал, что из нее что-то “заберут”.То есть проблема не в самом
std::move, а в том, что он всегда делает аргумент кандидатом на перемещение.Для perfect forwarding нужно использовать:
template <class T>
void wrapper(T&& value) {
process(std::forward<T>(value));
}
std::forward<T> сохраняет исходную категорию значения:• lvalue остается lvalue
• rvalue остается rvalue
А
std::move всегда говорит: “можно перемещать”.std::move часто слишком агрессивен. Если хочешь сохранить поведение аргумента — используй std::forward<T>.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍5❤4
Многопоточность — это не запуск нескольких thread. В реальных системах приходится управлять shared state, очередями задач, producer/consumer-потоками, read/write доступом и координацией выполнения.
На картинке — популярные multithreading patterns: read-write lock, thread pool, producer-consumer, future/promise и другие подходы, которые помогают организовать concurrent-код.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13🔥7🤝5
Быстро удаляем пробелы в начале и в конце строки!
Когда мы читаем строки из файла, пользовательского ввода или сетевого запроса — часто получаем "шум": пробелы, табы, переводы строк.
Во многих языках есть встроенные
Начнём с подключения нужных заголовков:
Теперь реализуем функцию
• пропускает все пробелы с начала строки;
• пропускает все пробелы с конца;
• возвращает обрезанную часть как новую строку:
Проверим, как это работает на примере строки с лишними пробелами и переводами строк:
Результат выполнения:
🔥 Теперь у тебя есть удобная функция, которая безопасно удаляет "мусор" по краям строки.
📣 C++ Ready | #практика
Когда мы читаем строки из файла, пользовательского ввода или сетевого запроса — часто получаем "шум": пробелы, табы, переводы строк.
Во многих языках есть встроенные
trim()-функции, но в C++ стандартной такой нет. Зато её легко реализовать самому — компактно, эффективно и без сторонних зависимостей.Начнём с подключения нужных заголовков:
#include <string>
#include <cctype> // std::isspace
#include <algorithm>
#include <iostream>
Теперь реализуем функцию
trim, которая:• пропускает все пробелы с начала строки;
• пропускает все пробелы с конца;
• возвращает обрезанную часть как новую строку:
std::string trim(const std::string& s) {
auto start = std::find_if_not(s.begin(), s.end(), ::isspace);
auto end = std::find_if_not(s.rbegin(), s.rend(), ::isspace).base();
return (start < end) ? std::string(start, end) : "";
}Проверим, как это работает на примере строки с лишними пробелами и переводами строк:
std::string raw = " \t\n Hello, world! \n ";
std::string cleaned = trim(raw);
std::cout << "[" << cleaned << "]\n";
Результат выполнения:
[Hello, world!]
🔥 Теперь у тебя есть удобная функция, которая безопасно удаляет "мусор" по краям строки.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤8👍4
This media is not supported in your browser
VIEW IN TELEGRAM
Внутри собраны базовые темы языка: переменные, циклы, функции, указатели, ООП, STL и другие важные вещи, которые нужны для понимания современного C++. Материал подан максимально понятно и с примерами кода, поэтому можно сразу запускать и разбирать, как всё работает на практике.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
❤20🔥7👍6👎2
Почему std::endl может тормозить программу?
Многие используют
Но
Сначала он добавляет перевод строки.
А потом принудительно сбрасывает буфер потока через flush.
В одном месте это может быть незаметно. Но если такой код стоит в цикле:
то программа может стать сильно медленнее.
Если тебе нужен просто перенос строки, чаще всего достаточно:
А
🔥 std::endl — это новая строка с принудительный flush. Стоит помнить это!
📣 C++ Ready | #совет
Многие используют
std::endl как обычный перевод строки:std::cout << i << std::endl;
Но
std::endl делает две вещи.Сначала он добавляет перевод строки.
А потом принудительно сбрасывает буфер потока через flush.
В одном месте это может быть незаметно. Но если такой код стоит в цикле:
for (int i = 0; i < 100000; ++i) {
std::cout << i << std::endl;
}то программа может стать сильно медленнее.
Если тебе нужен просто перенос строки, чаще всего достаточно:
std::cout << i << '\n';
А
std::endl стоит использовать тогда, когда flush действительно нужен.Please open Telegram to view this post
VIEW IN TELEGRAM
❤23👍6🔥5
Лёгкая утилита-«швейцарский нож» для TCP/UDP и UNIX-сокетов: слушает/устанавливает соединения, пересылает файлы, делает обратные оболочки, стримит и сканирует порты/граббинг баннеров.
Часто комбинируют с openssl, tar, dd для шифрования, архивации и клонирования.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤6👍4
Почему std::accumulate может неожиданно обрезать дроби?
На первый взгляд здесь всё нормально:
В vector лежат double, значит сумма тоже должна быть double.
Но есть нюанс. Тип аккумулятора задаётся третьим аргументом.
А 0 — это int.
Поэтому вычисление может идти через целочисленный аккумулятор, и дробная часть будет теряться.
Правильно так:
Теперь начальное значение — double, и сумма считается как double.
🔥 В std::accumulate третий аргумент — это не просто старт. Это тип всего вычисления.
📣 C++ Ready | #совет
На первый взгляд здесь всё нормально:
std::vector<double> v = {1.5, 2.5, 3.5};
auto sum = std::accumulate(v.begin(), v.end(), 0);В vector лежат double, значит сумма тоже должна быть double.
Но есть нюанс. Тип аккумулятора задаётся третьим аргументом.
А 0 — это int.
Поэтому вычисление может идти через целочисленный аккумулятор, и дробная часть будет теряться.
Правильно так:
auto sum = std::accumulate(v.begin(), v.end(), 0.0);
Теперь начальное значение — double, и сумма считается как double.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤16👍7🔥3🤝3
Генерируем случайный пароль на чистом C++!
Иногда нужно быстро создать случайную строку: временный пароль, токен для тестов или случайный идентификатор. Вручную выбирать символы неудобно, поэтому можно собрать маленький генератор с помощью стандартной библиотеки.
Для этого используем
Теперь создадим функцию, которая генерирует пароль нужной длины:
Теперь функцию можно вызвать из
При каждом запуске программа будет создавать новую случайную строку:
Внутри всё просто: мы задаём набор допустимых символов, случайно выбираем индекс из этого набора и добавляем выбранный символ в результат.
🔥 Генератор паролей на C++ — это простой способ увидеть
📣 C++ Ready | #практика
Иногда нужно быстро создать случайную строку: временный пароль, токен для тестов или случайный идентификатор. Вручную выбирать символы неудобно, поэтому можно собрать маленький генератор с помощью стандартной библиотеки.
Для этого используем
std::random_device, std::mt19937 и std::uniform_int_distribution.Теперь создадим функцию, которая генерирует пароль нужной длины:
std::string make_password(std::size_t length) {
const std::string chars =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"!@#$%^&*";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<std::size_t> dist(
0, chars.size() - 1
);
std::string result;
for (std::size_t i = 0; i < length; ++i) {
result += chars[dist(gen)];
}
return result;
}Теперь функцию можно вызвать из
main:int main() {
std::string password = make_password(12);
std::cout << "Password: " << password << '\n';
}При каждом запуске программа будет создавать новую случайную строку:
Password: a7K!pQ2z#Lm9
Внутри всё просто: мы задаём набор допустимых символов, случайно выбираем индекс из этого набора и добавляем выбранный символ в результат.
std::random в деле и сразу получить полезный результат.Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤5🔥4
This media is not supported in your browser
VIEW IN TELEGRAM
Здесь пошагово разбираются основы языка: переменные, циклы, функции, массивы, указатели, ООП, классы и другие важные темы. Всё объясняется простым языком с примерами кода и постепенным усложнением материала. Помимо основ, есть статьи по более продвинутым возможностям языка и практические примеры.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19❤6🤝6👍2