This media is not supported in your browser
VIEW IN TELEGRAM
Форум, где можно обсуждать задачи, получать помощь и разбирать кейсы из разработки. Есть активные разделы по C++ и C#: обсуждение синтаксиса, разбор ошибок, советы по обучению и практическая помощь. Форум можно использовать как источник знаний, особенно когда требуется разобраться в конкретной задаче или посмотреть, как её решают другие разработчик.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤20👍9🔥8
This media is not supported in your browser
VIEW IN TELEGRAM
Здесь публикуются подробные разборы ошибок, уязвимостей и практик разработки. Основной фокус на статический анализ кода и реальные кейсы из проектов, включая разборы популярных open-source решений. Блог активно покрывает C++ и C#: публикуются статьи по анализу, поиску багов, особенностям работы компиляторов и практике.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥9👍5
Как shared_ptr может привести к утечке памяти?
Потому что подсчет ссылок не умеет сам разрывать циклы.
Если два объекта держат друг друга через
Например, в такой схеме:
объект
Получается замкнутый круг: оба объекта остаются в памяти, потому что у каждого все еще есть хотя бы один владелец.
Именно поэтому
Чтобы разорвать цикл, одна из ссылок должна быть не владеющей:
🔥
📣 C++ Ready | #совет
Потому что подсчет ссылок не умеет сам разрывать циклы.
Если два объекта держат друг друга через
std::shared_ptr, их счетчики ссылок никогда не станут равны нулю. Даже когда внешний код уже “отпустил” оба объекта, они продолжают владеть друг другом.Например, в такой схеме:
struct A {
std::shared_ptr<B> b;
};
struct B {
std::shared_ptr<A> a;
};объект
A владеет B, а B владеет A.Получается замкнутый круг: оба объекта остаются в памяти, потому что у каждого все еще есть хотя бы один владелец.
Именно поэтому
shared_ptr не гарантирует автоматическое освобождение памяти во всех случаях.Чтобы разорвать цикл, одна из ссылок должна быть не владеющей:
struct B {
std::weak_ptr<A> a;
};std::weak_ptr не увеличивает счетчик владения, поэтому цикл исчезает, и объекты могут быть корректно уничтожены.shared_ptr считает владельцев, но не умеет сам разрывать циклы. Для этого нужен weak_ptr.Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤5🔥5
Например, CPU хорошо справляется с логикой, ветвлениями и задачами с низкой задержкой. GPU — про массовый параллелизм: подходит для обработки больших массивов данных, графики и вычислений.
На картинке — наглядное сравнение архитектуры, модели вычислений и типичных сценариев применения для каждого типа процессоров.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥9❤6
Меньше .first и .second: разбираем pair и tuple по-человечески!
Когда работаешь с
В C++17 для этого есть structured bindings. Они позволяют сразу разложить объект на именованные переменные.
Например, так можно пройтись по
Без structured bindings пришлось бы писать менее выразительно:
То же самое работает и с
Код становится короче и понятнее: вместо технических
🔥 Structured bindings делают код читаемее: меньше служебного шума, больше понятных имён.
📣 C++ Ready | #практика
Когда работаешь с
std::pair, std::tuple или элементами std::map, код быстро зарастает обращениями вроде .first, .second и std::get<0>(). Читать это неудобно, особенно если таких мест много.В C++17 для этого есть structured bindings. Они позволяют сразу разложить объект на именованные переменные.
Например, так можно пройтись по
std::map:#include <iostream>
#include <map>
#include <string>
std::map<std::string, int> scores{
{"alice", 10},
{"bob", 20}
};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << '\n';
}
Без structured bindings пришлось бы писать менее выразительно:
for (const auto& item : scores) {
std::cout << item.first << ": "
<< item.second << '\n';
}То же самое работает и с
std::pair:std::pair p{"error", 500};
auto [text, code] = p;
std::cout << text << ' ' << code << '\n';Код становится короче и понятнее: вместо технических
.first и .second появляются нормальные имена переменных, которые сразу передают смысл.Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍6🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
Это AI-инструмент для быстрого создания профессиональных презентаций. Достаточно добавить текст и идеи, а нейросеть автоматически подбирает дизайн, выравнивает элементы и формирует слайды. Встроенные умные шаблоны помогают делать презентации аккуратными без ручной настройки — AI сам адаптирует макет при добавлении контента.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤6🤝6
С их помощью можно автоматически определять тип переменной, изменять элементы контейнера по ссылке, безопасно обходить коллекции без копирования, удобно распаковывать пары и кортежиPlease open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21🤝13👍4❤3
Например,
код 200 означает, что всё прошло успешно, а 404 сообщает, что страница не найдена.Очень полезно держать под рукой, когда работаешь с API или отлаживаешь backend.
На картинке показаны самые часто используемые статусы от 100 до 599.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12❤8👍7
Разбираем безопасное побитовое преобразование типов!
Сейчас научимся преобразовывать данные одного типа в другой без неопределённого поведения — с помощью функции
Сначала подключим необходимые библиотеки из стандартной поставки:
Теперь создадим число с плавающей точкой и преобразуем его в
Преобразуем обратно, чтобы убедиться, что значение не потеряно:
Результат при запуске программы:
🔥 Таким образом ты можешь безопасно перепаковывать данные между типами одинакового размера — без UB, memcpy и хаков.
📣 C++ Ready | #практика
Сейчас научимся преобразовывать данные одного типа в другой без неопределённого поведения — с помощью функции
std::bit_cast.Сначала подключим необходимые библиотеки из стандартной поставки:
#include <bit> // std::bit_cast
#include <cstdint> // uint32_t
#include <iostream>
#include <iomanip> // std::hex, std::setw, std::setfill
Теперь создадим число с плавающей точкой и преобразуем его в
uint32_t, чтобы увидеть его внутреннее битовое представление:float value = 3.1415926f;
uint32_t raw = std::bit_cast<uint32_t>(value);
std::cout << "Биты числа: 0x"
<< std::hex << std::setw(8) << std::setfill('0') << raw << '\n';
Преобразуем обратно, чтобы убедиться, что значение не потеряно:
float restored = std::bit_cast<float>(raw);
std::cout << std::dec << "Восстановлено: " << restored << '\n';
Результат при запуске программы:
Биты числа: 0x40490fda
Восстановлено: 3.14159
🔥 Таким образом ты можешь безопасно перепаковывать данные между типами одинакового размера — без UB, memcpy и хаков.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12❤8👍5
This media is not supported in your browser
VIEW IN TELEGRAM
Этот репозиторий собирает лучшие гайды, где вместо теории — реальные проекты, которые можно реализовать с нуля. Внутри есть десятки идей. В разделах по C++ и C# можно найти идеи разного уровня: работа с файлами, сетевое взаимодействие, графика, многопоточность и др. задачи.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18❤9🔥6
Почему push_back() во время обхода vector может привести к багу?
Потому что при добавлении нового элемента
Проблема в том, что range-based for тоже опирается на итераторы. И если внутри цикла вызвать:
контейнер может переехать в другую область памяти. Тогда цикл продолжит работу уже с невалидными итераторами, а это undefined behavior.
То есть внешне код выглядит безобидно, но в реальности может:
• работать “случайно нормально”
• пропускать элементы
• падать
• давать нестабильное поведение
Особенно неприятно, что такой баг может проявляться не всегда, а только при определенном размере контейнера.
🔥 У
📣 C++ Ready | #совет
Потому что при добавлении нового элемента
std::vector может перевыделить память. А после этого все итераторы, ссылки и указатели на его элементы становятся невалидными.Проблема в том, что range-based for тоже опирается на итераторы. И если внутри цикла вызвать:
v.push_back(5);
контейнер может переехать в другую область памяти. Тогда цикл продолжит работу уже с невалидными итераторами, а это undefined behavior.
То есть внешне код выглядит безобидно, но в реальности может:
• работать “случайно нормально”
• пропускать элементы
• падать
• давать нестабильное поведение
Особенно неприятно, что такой баг может проявляться не всегда, а только при определенном размере контейнера.
vector добавление элемента может инвалидировать итераторы. Менять контейнер во время его обхода нужно очень осторожно.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16👍5❤4
Например, регистры — это самый быстрый уровень памяти внутри CPU, кэш (L1/L2/L3) снижает latency за счёт локальности данных, RAM хранит рабочее состояние приложений, а SSD/HDD используются для персистентного хранения с существенно более высоким временем доступа.
На картинке — базовая иерархия памяти, взаимодействие CPU — cache — RAM — disk, а также упрощённая модель работы HDD и архитектура SSD.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤19👍9🔥6
Не копировать объект, а просто обменять: std::swap как базовый инструмент
Иногда нужно просто поменять значения двух переменных местами. Вручную это обычно делают через временную переменную, но в C++ для этого уже есть готовый и понятный инструмент —
Простой пример:
После вызова значения переменных меняются местами:
То же самое работает не только с числами, но и с контейнерами:
Такой обмен обычно дешевле и чище, чем ручное переприсваивание. А главное — сразу видно намерение: мы не “что-то присваиваем”, а именно меняем объекты местами.
🔥
📣 C++ Ready | #практика
Иногда нужно просто поменять значения двух переменных местами. Вручную это обычно делают через временную переменную, но в C++ для этого уже есть готовый и понятный инструмент —
std::swap.Простой пример:
int a = 10;
int b = 20;
std::swap(a, b);
std::cout << a << ' ' << b << '\n';
После вызова значения переменных меняются местами:
a == 20b == 10То же самое работает не только с числами, но и с контейнерами:
std::vector<int> x{1, 2, 3};
std::vector<int> y{4, 5};
std::swap(x, y);
std::cout << x.size() << ' ' << y.size() << '\n';Такой обмен обычно дешевле и чище, чем ручное переприсваивание. А главное — сразу видно намерение: мы не “что-то присваиваем”, а именно меняем объекты местами.
std::swap делает код проще и выразительнее: обмен значений — одной строкой и без лишнего шума.Please open Telegram to view this post
VIEW IN TELEGRAM
👍23❤6🔥6👎1
This media is not supported in your browser
VIEW IN TELEGRAM
Это структурированный обучающий сайт, где собрано более 200 уроков по C++, охватывающих как базовые, так и углублённые темы языка. Отдельное внимание уделено практике: на сайте есть задания, проекты и даже разборы создания игр, что позволяет применять знания в реальных задачах.
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤14🔥10👍6
Почему после push_back() нельзя слепо использовать старый итератор?
Потому что
Если при добавлении нового элемента текущей capacity уже не хватает, вектор перевыделяет память и переносит элементы в новое место.
После этого все итераторы, ссылки и указатели на старые элементы становятся невалидными.
В таком коде:
Если во время
Из-за этого баг особенно неприятный: код может
* работать “нормально” на маленьких примерах,
* ломаться только на других данных,
* проявляться нестабильно и не сразу.
Если после изменения
А если хочешь уменьшить шанс перевыделения памяти, можно заранее вызвать
🔥 У
📣 C++ Ready | #совет
Потому что
std::vector хранит элементы в непрерывной области памяти.Если при добавлении нового элемента текущей capacity уже не хватает, вектор перевыделяет память и переносит элементы в новое место.
После этого все итераторы, ссылки и указатели на старые элементы становятся невалидными.
В таком коде:
std::vector<int> v = {1, 2, 3};
auto it = v.begin();
v.push_back(4);
std::cout << *it << "\n";it мог указывать на элемент в старом буфере памяти.Если во время
push_back() произошел reallocation, разыменование it — это уже undefined behavior.Из-за этого баг особенно неприятный: код может
* работать “нормально” на маленьких примерах,
* ломаться только на других данных,
* проявляться нестабильно и не сразу.
Если после изменения
vector тебе снова нужен итератор, его лучше получить заново.А если хочешь уменьшить шанс перевыделения памяти, можно заранее вызвать
reserve().vector итераторы живут только до тех пор, пока контейнер не изменил свое хранилище.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤4🤝4😁1
В этой статье:
• Как создать окно SFML и настроить главный цикл с обработкой событий• Реализация singleton-контроллера для управления движением по клавишам• Подключение и отображение текстур в игровом цикле🔊 Советую продолжить читать на Habr!
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
🔥28🤝5❤4😁1