<MyRusakov.ru />

Создание нейросетей на Python

Создание нейросетей на Python

Этот курс научит Вас созданию нейросетей на Python. Курс рассчитан на начинающих. Вся информация идёт от простого к сложному очень маленькими шажками. При этом глубокое знание математики не требуется. Поскольку в курсе Вы будете получать эти знания по мере необходимости.

Из курса Вы узнаете всю необходимую теорию и терминологию. Научитесь создавать нейросети самых разных архитектур и обучать их. Также Вы создадите собственный фреймворк. Что очень важно проделать для грамотного использования того же PyTorch. Затем Вы изучите и сам PyTorch.

Помимо уроков к курсу идут упражнения для закрепления материала.

Ещё Вы получите Бонусы, дополняющие основной курс: "Распознавание изображений", "Анализ настроения по тексту отзыва", "Программирование на Python с Нуля до Гуру".

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

Умные указатели в C++: понятное руководство по unique_ptr, shared_ptr и weak_ptr с примерами

Умные указатели в C++: понятное руководство по unique_ptr, shared_ptr и weak_ptr с примерами

Запрос «умные указатели в C++ примеры» стабильно популярен: новичкам сложно сразу понять, чем отличаются unique_ptr, shared_ptr и weak_ptr, а продолжающим — где их применять без лишнего оверхеда. В этом руководстве мы разберем каждую модель владения, типичные ошибки и покажем рабочие примеры, которые пригодятся в реальных проектах.

Что решают умные указатели в C++

Умные указатели — это RAII-обертки вокруг «сырых» указателей (raw pointers), которые автоматически освобождают ресурсы при выходе из области видимости. Это снижает риск утечек памяти, упрощает владение и делает код безопаснее. Главные герои: std::unique_ptr, std::shared_ptr и std::weak_ptr.

std::unique_ptr: единственный владелец

unique_ptr гарантирует уникальное владение объектом. Нельзя копировать, но можно перемещать. Идеален по умолчанию, если объектом владеет ровно одна сущность.

#include <memory>
#include <iostream>
#include <vector>

struct Widget {
    int id;
    explicit Widget(int i) : id(i) { std::cout << "Widget(" << id << ")\n"; }
    ~Widget() { std::cout << "~Widget(" << id << ")\n"; }
};

int main() {
    auto p = std::make_unique<Widget>(42);        // создание
    std::vector<std::unique_ptr<Widget>> v;
    v.push_back(std::move(p));                     // перенос владения в вектор
    // p теперь пуст (nullptr)
}

Передача владения в функцию — по значению unique_ptr (с перемещением):

void take(std::unique_ptr<Widget> w) {
    // w - новый владелец
}

void use(const Widget& w) {
    // только пользуемся, не владеем
}

int main() {
    auto p = std::make_unique<Widget>(1);
    use(*p);
    take(std::move(p));
}

Можно хранить в контейнерах, использовать полиморфизм и безопасно управлять массивами:

struct Base { virtual ~Base() = default; virtual void f() = 0; };
struct Derived : Base { void f() override { std::cout << "Derived\n"; } };

int main() {
    std::unique_ptr<Base> pb = std::make_unique<Derived>();
    pb->f();

    auto arr = std::make_unique<int[]>(5); // динамический массив
    arr[0] = 10;
}

Кастомные делетеры делают unique_ptr универсальным для системных ресурсов:

#include <cstdio>
using FilePtr = std::unique_ptr<FILE, decltype(&std::fclose)>;

FilePtr openFile(const char* path) {
    FILE* f = std::fopen(path, "r");
    return FilePtr(f, &std::fclose);
}

std::shared_ptr: разделяемое владение

shared_ptr считает количество владельцев и освобождает ресурс, когда счетчик доходит до нуля. Удобен, когда объект делят несколько частей системы (например, граф сцены, кэш, пул).

#include <memory>
#include <iostream>

struct Data { int v; explicit Data(int x) : v(x) {} };

int main() {
    auto a = std::make_shared<Data>(10);
    auto b = a; // еще один владелец
    std::cout << a.use_count() << " owners\n"; // 2
    b.reset();
    std::cout << a.use_count() << " owners\n"; // 1
}

Важно: увеличение/уменьшение счетчика потокобезопасно, но сам объект нет. Если объект используется из нескольких потоков, защитите доступ мьютексами.

std::weak_ptr: наблюдатель без владения

weak_ptr не продлевает жизнь объекта. Используется, чтобы разорвать циклы владения и устраивать безопасные ссылки-наблюдатели.

#include <memory>
#include <iostream>

int main() {
    std::weak_ptr<int> wp;
    {
        auto sp = std::make_shared<int>(5);
        wp = sp; // наблюдаем за sp
        if (auto locked = wp.lock()) {
            std::cout << *locked << "\n";
        }
    } // sp уничтожен

    if (auto locked = wp.lock()) {
        std::cout << *locked << "\n";
    } else {
        std::cout << "expired\n";
    }
}

Циклические ссылки: типичная ловушка shared_ptr

Два объекта, ссылающихся друг на друга shared_ptr-ами, никогда не освободятся — счетчики не станут нулем. Решение: одна сторона хранит weak_ptr.

#include <memory>
struct Node {
    int value{};
    std::shared_ptr<Node> next;
    std::weak_ptr<Node>   prev; // разрываем цикл слабой ссылкой
};

shared_from_this: безопасно получить shared_ptr из this

Если объект уже управляется shared_ptr, а вам нужен еще один shared_ptr на него внутри метода — используйте enable_shared_from_this.

#include <memory>
#include <iostream>

struct Session : std::enable_shared_from_this<Session> {
    void start() {
        auto self = shared_from_this(); // безопасно
        std::cout << "owners: " << self.use_count() << "\n";
    }
};

int main() {
    auto s = std::make_shared<Session>();
    s->start();
}

Нельзя вызывать shared_from_this(), если объект не был создан под управлением shared_ptr — будет исключение.

Как передавать умные указатели в функции

  • Нужно просто «пользоваться» объектом: const T& или T& (без владения).
  • Нужно передать владение единственному получателю: std::unique_ptr<T> по значению (вызывать std::move при вызове).
  • Нужно разделить владение: std::shared_ptr<T> по значению или по const std::shared_ptr<T>& для экономии инкремента/декремента счетчика при частых вызовах.
  • Нужно «слабое» наблюдение: std::weak_ptr<T> и внутри функции lock().
  • Сырые указатели T* годятся только как невладеющие ссылки для совместимости с C-APIs, но в современном коде предпочтительнее ссылки &.

Производительность и практические советы

  • std::make_unique и std::make_shared — предпочтительные фабрики. make_shared делает одну аллокацию для объекта и контрольного блока, что быстрее и кеш-дружелюбнее.
  • Не смешивайте владение: если у вас есть shared_ptr<T>, не создавайте параллельный unique_ptr<T> на тот же объект — поведение неопределено.
  • Не «делитесь» владением через get(): сырые указатели из get() не увеличивают счетчик, легко получить use-after-free.
  • Кастомный делетер поддерживается в shared_ptr через конструктор, но не поддерживается в make_shared. Если нужен делетер — используйте shared_ptr<T>(new T, Deleter).
  • Для наблюдателей в паттерне «наблюдатель» используйте weak_ptr, чтобы не держать объект вечно живым.

Мини-чеклист выбора

  • Владение одно: unique_ptr (по умолчанию).
  • Владение разделяется: shared_ptr (осознанно, за счет накладных расходов).
  • Наблюдение без владения: weak_ptr.
  • Нужны массивы: unique_ptr<T[]> или контейнеры STL (vector, string, и т.д.).
  • Нужна скорость и простота — избегайте shared_ptr без необходимости.

Типичные вопросы на собеседовании

  • Чем отличается unique_ptr от shared_ptr по затратам? (shared_ptr хранит контрольный блок и атомарно меняет счетчик — дороже).
  • Когда нужен weak_ptr? (разрыв циклов и наблюдение без продления жизни).
  • Почему стоит предпочитать make_unique/make_shared? (исключительная безопасность и меньше аллокаций).
  • Как передавать unique_ptr в функцию? (по значению + std::move).

Где потренироваться и закрыть пробелы

Если хотите быстро отточить навыки и пройти практику с задачами и разбором, рекомендую посмотреть программу курса: Практический интенсив «Программирование на C++ с Нуля до Гуру» — стартуйте и прокачайте C++ до уровня проектов.

Итоги

Умные указатели в C++ — базовый инструмент современного кода. Используйте unique_ptr по умолчанию, подключайте shared_ptr только при реальной необходимости разделения владения, а weak_ptr — для безопасных наблюдений и разрыва циклов. Следуя этим правилам и примерам, вы избежите утечек памяти, упростите дизайн и сделаете код надежнее и быстрее.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.