Зачем в C++ помечать важные результаты через [[nodiscard]]?
Иногда функция возвращает значение, которое нельзя просто проигнорировать: статус операции, ошибку, открытый ресурс, результат валидации.
Например:
Код компилируется, но результат потерян. Если сохранение не удалось, программа может продолжить работу так, будто всё нормально.
Для таких случаев есть атрибут [[nodiscard]]:
Теперь компилятор предупредит, если результат вызова проигнорировали:
Правильнее явно обработать результат:
Особенно полезно помечать функции, которые возвращают объект ошибки:
Или результат проверки:
Если результат действительно нужно проигнорировать, лучше показать это явно:
Так сразу видно, что разработчик сделал это осознанно, а не случайно.
📣 C++ Ready | #совет
Иногда функция возвращает значение, которое нельзя просто проигнорировать: статус операции, ошибку, открытый ресурс, результат валидации.
Например:
bool save_config() {
return write_file("config.json");
}
save_config();Код компилируется, но результат потерян. Если сохранение не удалось, программа может продолжить работу так, будто всё нормально.
Для таких случаев есть атрибут [[nodiscard]]:
[[nodiscard]]
bool save_config() {
return write_file("config.json");
}
Теперь компилятор предупредит, если результат вызова проигнорировали:
save_config(); // warning
Правильнее явно обработать результат:
if (!save_config()) {
std::cerr << "Config was not saved\n";
}Особенно полезно помечать функции, которые возвращают объект ошибки:
[[nodiscard]]
std::optional<User> find_user(int id);
Или результат проверки:
[[nodiscard]]
bool is_valid_token(std::string_view token);
Если результат действительно нужно проигнорировать, лучше показать это явно:
(void)save_config();
Так сразу видно, что разработчик сделал это осознанно, а не случайно.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍7🔥3
Интересная статья про компилятор на C++ и LLVM!
Автор рассказывает, как писал собственный язык Marble и постепенно собирал вокруг него lexer, parser, AST, генерацию LLVM IR и диагностику ошибок.
В статье автор показывает:
• как разбить компилятор на понятные этапы
• зачем нужен AST перед генерацией LLVM IR
• как обрабатывать ошибки так, чтобы язык было реально удобно развивать
📣 C++ Ready | #статья
Автор рассказывает, как писал собственный язык Marble и постепенно собирал вокруг него lexer, parser, AST, генерацию LLVM IR и диагностику ошибок.
В статье автор показывает:
• как разбить компилятор на понятные этапы
• зачем нужен AST перед генерацией LLVM IR
• как обрабатывать ошибки так, чтобы язык было реально удобно развивать
Продолжай читать на Habr
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤4🔥3😁1
Почему structured binding может неожиданно копировать данные?
В C++ structured binding удобно распаковывает пары, tuple и элементы map:
Но здесь
Если изменить
Для маленьких чисел это неважно, но для строк, векторов и больших объектов можно получить лишние копирования.
Если нужно работать с исходными значениями, используй ссылку:
Теперь меняется сам объект:
То же самое часто встречается при обходе map:
Такой код меняет копию value, а не элемент внутри map.
Правильно, если нужно менять данные:
А если нужно только читать без копий:
Structured binding удобная штука. Для реальных данных чаще нужны
📣 C++ Ready | #совет
В C++ structured binding удобно распаковывает пары, tuple и элементы map:
auto item = std::pair{1, std::string("ready")};
auto [id, name] = item;Но здесь
id и name это копии значений из item.Если изменить
name, исходная пара не изменится:name = "cpp";
std::cout << item.second; // ready
Для маленьких чисел это неважно, но для строк, векторов и больших объектов можно получить лишние копирования.
Если нужно работать с исходными значениями, используй ссылку:
auto& [id, name] = item;
name = "cpp";
Теперь меняется сам объект:
std::cout << item.second; // cpp
То же самое часто встречается при обходе map:
for (auto [key, value] : users) {
value.active = false;
}Такой код меняет копию value, а не элемент внутри map.
Правильно, если нужно менять данные:
for (auto& [key, value] : users) {
value.active = false;
}А если нужно только читать без копий:
for (const auto& [key, value] : users) {
std::cout << key << value.name;
}Structured binding удобная штука. Для реальных данных чаще нужны
auto& или const auto&.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍5🔥5
Шпаргалка по std::move в алгоритмах C++!
Например, std::move из <algorithm> переносит элементы из одного диапазона в другой. Это не то же самое, что std::move из <utility>, который просто превращает объект в rvalue.
На картинке показано, как работает алгоритм move. Есть исходный диапазон, целевой диапазон, возвращаемый итератор и вариант ranges::move из C++20.
Сохрани, чтобы не потерять!
📣 C++ Ready | #ресурс
Например, std::move из <algorithm> переносит элементы из одного диапазона в другой. Это не то же самое, что std::move из <utility>, который просто превращает объект в rvalue.
На картинке показано, как работает алгоритм move. Есть исходный диапазон, целевой диапазон, возвращаемый итератор и вариант ranges::move из C++20.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍5🔥3
Фильтруем файлы по расширению через std::filesystem!
Иногда нужно быстро пройтись по папке и выбрать только нужные файлы. Например, найти все .log, .json, .txt или .cpp файлы для дальнейшей обработки.
Для этого удобно использовать std::filesystem. Он даёт нормальные типы для путей, директорий и файлов без ручной склейки строк.
Сначала зададим директорию и нужное расширение:
Теперь можно пройти по директории рекурсивно:
Важно не обрабатывать директории как файлы. Поэтому сначала проверяем тип элемента:
После этого сравниваем расширение через path::extension:
Такой код не зависит от ручного поиска точки в имени файла. Если путь содержит несколько точек или вложенные папки, filesystem всё равно корректно выделит расширение.
Можно легко заменить действие внутри if. Вместо вывода в консоль файл можно прочитать, добавить в список, посчитать размер или передать в другую функцию.
📣 C++ Ready | #практика
Иногда нужно быстро пройтись по папке и выбрать только нужные файлы. Например, найти все .log, .json, .txt или .cpp файлы для дальнейшей обработки.
Для этого удобно использовать std::filesystem. Он даёт нормальные типы для путей, директорий и файлов без ручной склейки строк.
Сначала зададим директорию и нужное расширение:
namespace fs = std::filesystem;
fs::path root = "logs";
std::string ext = ".log";
Теперь можно пройти по директории рекурсивно:
for (const auto& entry : fs::recursive_directory_iterator(root)) {
// проверяем каждый элемент
}Важно не обрабатывать директории как файлы. Поэтому сначала проверяем тип элемента:
if (!entry.is_regular_file()) {
continue;
}После этого сравниваем расширение через path::extension:
if (entry.path().extension() == ext) {
std::cout << entry.path() << "\n";
}Такой код не зависит от ручного поиска точки в имени файла. Если путь содержит несколько точек или вложенные папки, filesystem всё равно корректно выделит расширение.
Можно легко заменить действие внутри if. Вместо вывода в консоль файл можно прочитать, добавить в список, посчитать размер или передать в другую функцию.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍4🔥3
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤4👍1
Почему ссылка на элемент vector может внезапно сломаться?
Иногда хочется сохранить ссылку на элемент, а потом продолжить добавлять данные:
На вид всё спокойно: ссылка указывает на первый элемент.
Но если при
После этого старая ссылка уже невалидна:
Такой код может вывести старое значение, мусор или вообще повести себя непредсказуемо.
Если нужно хранить позицию, безопаснее сохранить индекс:
А если заранее понятно, сколько элементов будет добавлено, можно уменьшить риск перераспределения:
В
📣 C++ Ready | #совет
Иногда хочется сохранить ссылку на элемент, а потом продолжить добавлять данные:
std::vector<int> nums{10, 20};
int& first = nums[0];
nums.push_back(30);На вид всё спокойно: ссылка указывает на первый элемент.
Но если при
push_back() вектору не хватит места, он выделит новый блок памяти и перенесёт туда элементы.После этого старая ссылка уже невалидна:
std::cout << first;
Такой код может вывести старое значение, мусор или вообще повести себя непредсказуемо.
Если нужно хранить позицию, безопаснее сохранить индекс:
std::size_t index = 0;
nums.push_back(30);
std::cout << nums[index];
А если заранее понятно, сколько элементов будет добавлено, можно уменьшить риск перераспределения:
nums.reserve(100);
В
std::vector ссылки, указатели и итераторы могут стать невалидными после роста контейнера. Если контейнер меняется лучше хранить индекс или заново получать элемент.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍6❤3
Собираем scope guard для автоматического отката!
Иногда функция успевает изменить состояние, открыть ресурс или создать временный файл, а потом падает на следующем шаге. Вручную расставлять cleanup перед каждым return неудобно и легко забыть.
В этой задаче:
Код полезен для временных файлов, lock-файлов и rollback действий, где важно не оставить систему в промежуточном состоянии.
📣 C++ Ready | #задача
Иногда функция успевает изменить состояние, открыть ресурс или создать временный файл, а потом падает на следующем шаге. Вручную расставлять cleanup перед каждым return неудобно и легко забыть.
В этой задаче:
• сохраняем cleanup-функцию
• запускаем её в деструкторе
• отключаем cleanup после успешного завершения
• используем guard как маленькую защиту от ранних выходов
Код полезен для временных файлов, lock-файлов и rollback действий, где важно не оставить систему в промежуточном состоянии.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥2
7,2 млн рублей призового фонда и реальные задачи космической отрасли 🚀
В сентябре пройдет серия КосмоХакатонов для студентов, молодых ученых и специалистов.
Участникам предстоит за два дня разработать собственное решение, поработать с экспертами и представить проект жюри.
Участников ждут:
🛰 реальные задачи космической отрасли
👥 команды от 3 до 5 человек
💻 очный и онлайн-форматы
🧑💻 работа с экспертами и трекерами
🏆 финал в Москве
Первый КосмоХакатон стартует уже 4 сентября в Ростове-на-Дону.
Дальше серия продолжится в Красноярске, Нижнем Новгороде, Благовещенске и Санкт-Петербурге, а завершится финалом в Москве.
Участие бесплатное. Присоединиться могут студенты, аспиранты, молодые ученые и специалисты от 18 лет.
🔗 Зарегистрироваться: https://космохакатон.рф
В сентябре пройдет серия КосмоХакатонов для студентов, молодых ученых и специалистов.
Участникам предстоит за два дня разработать собственное решение, поработать с экспертами и представить проект жюри.
Участников ждут:
🛰 реальные задачи космической отрасли
👥 команды от 3 до 5 человек
💻 очный и онлайн-форматы
🧑💻 работа с экспертами и трекерами
🏆 финал в Москве
Первый КосмоХакатон стартует уже 4 сентября в Ростове-на-Дону.
Дальше серия продолжится в Красноярске, Нижнем Новгороде, Благовещенске и Санкт-Петербурге, а завершится финалом в Москве.
Участие бесплатное. Присоединиться могут студенты, аспиранты, молодые ученые и специалисты от 18 лет.
🔗 Зарегистрироваться: https://космохакатон.рф
👍1
Почему std::vector<bool> может вести себя странно?
На первый взгляд vector<bool> выглядит как обычный vector, только для логических значений. Кажется, что каждый элемент там настоящий bool.
Но у этого контейнера есть специальная оптимизация. Он может хранить значения битами, поэтому обращение к элементу возвращает не bool&, а proxy-объект.
Обычный код выглядит нормально:
Проблемы начинаются, когда хочется взять ссылку на элемент:
Такой код может не сработать так, как ожидается, потому что flags[0] не является настоящей ссылкой на bool.
Даже auto может скрыть нюанс:
Здесь item часто остаётся proxy-объектом, который связан с контейнером. Код читается как работа с копией, но на деле может менять исходный vector.
Если нужен обычный массив флагов без таких сюрпризов, часто проще взять другой тип:
А если важна компактная битовая упаковка, лучше явно показать намерение:
vector<bool> не запрещён, но его лучше не воспринимать как обычный vector<T>. Особенно в шаблонном коде, где ожидаются настоящие ссылки на элементы.
📣 C++ Ready | #совет
На первый взгляд vector<bool> выглядит как обычный vector, только для логических значений. Кажется, что каждый элемент там настоящий bool.
Но у этого контейнера есть специальная оптимизация. Он может хранить значения битами, поэтому обращение к элементу возвращает не bool&, а proxy-объект.
Обычный код выглядит нормально:
std::vector<bool> flags = {true, false};
flags[1] = true;Проблемы начинаются, когда хочется взять ссылку на элемент:
auto& item = flags[0];
Такой код может не сработать так, как ожидается, потому что flags[0] не является настоящей ссылкой на bool.
Даже auto может скрыть нюанс:
auto item = flags[0];
item = false;
Здесь item часто остаётся proxy-объектом, который связан с контейнером. Код читается как работа с копией, но на деле может менять исходный vector.
Если нужен обычный массив флагов без таких сюрпризов, часто проще взять другой тип:
std::vector<char> flags;
std::vector<uint8_t> mask;
А если важна компактная битовая упаковка, лучше явно показать намерение:
std::bitset<64> flags;
vector<bool> не запрещён, но его лучше не воспринимать как обычный vector<T>. Особенно в шаблонном коде, где ожидаются настоящие ссылки на элементы.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍8🔥4
Сильная статья про high performance на C++ для CPU!
Автор объясняет, как подходить к ускорению кода. Разбирается CPU, кеши, профилирование, бенчмарки, sanitizers и понимание узких мест.
В статье автор показывает:
• почему сначала нужно искать bottleneck
• как кэш CPU и доступ к памяти влияют на скорость
• зачем нужны бенчмарки, профилирование и санитайзеры
📣 C++ Ready | #статья
Автор объясняет, как подходить к ускорению кода. Разбирается CPU, кеши, профилирование, бенчмарки, sanitizers и понимание узких мест.
В статье автор показывает:
• почему сначала нужно искать bottleneck
• как кэш CPU и доступ к памяти влияют на скорость
• зачем нужны бенчмарки, профилирование и санитайзеры
Продолжай читать на Habr
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍7🔥4
Шпаргалка по smart pointers в C++!
Например, std::unique_ptr показывает единственное владение объектом, std::shared_ptr разделяет владение через счётчик ссылок, а std::weak_ptr помогает наблюдать объект без продления его жизни.
На картинке собраны основные правила работы со smart pointers. Есть std::unique_ptr, std::shared_ptr, std::weak_ptr, make_unique, make_shared, custom deleters, lock, reset, get и важные нюансы владения.
Сохрани, чтобы не потерять!
📣 C++ Ready | #ресурс
Например, std::unique_ptr показывает единственное владение объектом, std::shared_ptr разделяет владение через счётчик ссылок, а std::weak_ptr помогает наблюдать объект без продления его жизни.
На картинке собраны основные правила работы со smart pointers. Есть std::unique_ptr, std::shared_ptr, std::weak_ptr, make_unique, make_shared, custom deleters, lock, reset, get и важные нюансы владения.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍4🔥3