C++ lectures at MIPT (in Russian). Lecture 9. Smart pointers, part 1

Поделиться
HTML-код
  • Опубликовано: 3 окт 2024
  • Лекции в магистратуре МФТИ по C++ на русском языке.
    Эта лекция посвящена очень простым и базовым вещам: владению ресурсами (и в частности памятью) и моделям такого владения.
    Заканчивается лекция рассмотрением вариантных типов
    Лектор: Константин Владимиров
    Дата лекции: 26 ноября 2019 года
    Съёмка и звук: Дмитрий Рябцев
    Предыдущая лекция: • C++ lectures at MIPT (...
    Следующая лекция: • C++ lectures at MIPT (...
    Слайды ко всем лекциям: sourceforge.ne...
    Errata:
    пока здесь пусто

Комментарии • 34

  • @kimve1969
    @kimve1969 7 месяцев назад +1

    Супер лекции!

  • @eamirus1
    @eamirus1 4 года назад +4

    Большое спасибо за все лекции, до просмотра этого видео кучу раз читал, но ни разу не понимал смартпоинтеры, теперь ситуация точно проясняется.)

  • @zahar.lebediuk
    @zahar.lebediuk 2 года назад +4

    Вот я вроде бы всё понимаю в лекциях, тяну руку и правильно отвечаю(за монитором самому себе :D) но когда вы говорите подумать дома над какой-то задачкой, то у меня идей вообще нет... Надеюсь со временем, когда количество знаний увеличиться, то я смогу обдумывать решения таких задач! Спасибо за лекции!

    • @tilir
      @tilir  2 года назад

      А что именно из заданий в этой лекции вызвало затруднения и почему?

  • @tableman3912
    @tableman3912 2 года назад

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

    • @tilir
      @tilir  2 года назад +1

      Лямбды будут на своём месте -- перед алгоритмами. Базовые вещи о них были сообщены в первых лекциях. Детали последуют.

    • @tableman3912
      @tableman3912 2 года назад

      @@tilir прошу прощения, это я случайно перескочил между курсами. В старом курсе были лямбды в начале, поэтому все ими оперируют.

  • @samolisov
    @samolisov 2 года назад

    По поводу замечания, что интерфейс голого указателя предполагает, что ему всегда можно сделать delete. Это порождает довольно интересный спор по поводу, а вот мне нужно в функцию передать указатель, но без передачи владения, чтобы она там что-то поделала с ним или целевым объектом и все. Если по фен-шую, у нас везде умные указатели и мы не хотим, чтобы утек голый указатель, то надо передавать по константной ссылке на unique_ptr. Но это жесть: const std::unique_ptr& param. А если это библиотека, и не факт, что там будет unique_ptr, а не shared_ptr? Знаю ещё, что в core guidelines есть owner, чтобы показать, что вот тут мы указателем владеем, во всех остальных случаях сырой указатель это значит, что не владеем и delete делать не следует. А вы какой стратегии придерживаетесь?

    • @tilir
      @tilir  2 года назад

      Ссылка на unique_ptr звучит для меня очень странно. Вы либо передаёте просто по ссылке. Либо умный указатель по значению, т.к. у нас и так ссылочная семантика для указателей.
      Я плохо могу представить зачем вам передавать голый указатель не передавая владения. Разве что какая-нибудь реализация дерева, например, но пока это в приватной части это терпимо.

  • @dmitriylosev6832
    @dmitriylosev6832 3 года назад

    5:55
    T& operator*() const
    (Если мы хотим сохранять дизайн обычного поинтера)
    30:00
    unique_ptr& operator=(unique_ptr&& rhs) {
    delete ptr_;
    ptr_ = rhs.ptr_;
    rhs.ptr_ = nullptr;
    return *this;
    }
    (По смыслу мы же хотим передать владение от rhs к *this, а не обменять владение)

    • @tilir
      @tilir  3 года назад

      (1) Согласен. Но там в коде есть гораздо худшая логическая ошибка.
      (2) Зачем? Смотрите: после A = move(B), B переходит в moved-from состояние. То есть согласованное но непредсказуемое. Вариантом этого состояния является прошлое состояние A. Нет никаких оснований тут вызывать сравнительно дорогой delete. По семантике вполне безопасно просто поменять (и это быстрее).

    • @dmitriylosev6832
      @dmitriylosev6832 3 года назад

      @@tilir (2) Ok. Но тогда нужно сделать swap(ptr_, rhs.ptr_); При swap(*this, rhs) сейчас будет stackoverflow.

  • @ВячеславШляга
    @ВячеславШляга 2 года назад

    На 17 слайде наверное ошибка. Конструктор копирования unique_ptr(const unique_ptr &rhs) = delete а не unique_ptr(unique_ptr &rhs) = delete

    • @tilir
      @tilir  2 года назад

      Нет разницы. Обе формы это допустимые формы для copy ctor. Запрет любой из них это запрет копирования.

  • @victormustya1745
    @victormustya1745 4 года назад +1

    Будет ли раскрыта тема intrusive pointers? Ну хотя бы на примере boost::intrusive_ptr. Их использование бывает необходимо, когда код на C++ интегрируется с кодом на динамических языках

    • @tilir
      @tilir  4 года назад

      Да, это будет во второй части ))

  • @d7d1cd
    @d7d1cd 3 года назад

    Константин, мне непонятно почему возвращать сырой указатель из самописного "умного" указателя это плохо. Понятно, что к нему могут применить delete. Но ведь и из std::string можно получить сырой указатель на первый символ и применить delete. Мне кажется, если кто-то применяет delete к сырому указателю, не выделив перед этим память, то он ССЗБ. Поэтому, как мне кажется, возвращать сырой указатель - это нормально...
    А еще в функцию bar можно было передать ссылку на scoped_ptr.

    • @tilir
      @tilir  3 года назад +1

      У строки есть иное предназначение. Это строка, она предоставляет интерфейс строки, итераторы и всё такое
      У умного указателя есть только одно предназначение: владеть объектом и управлять его временем жизни. Как только ресурс утёк по сырому указателю, умный указатель лишается смысла. И delete там не худшее что может произойти. Например если у вас есть unique_ptr и вы обещаете что он не утёк, он, с точки зрения многопоточности, ведёт себя как int: достаточно мьютекса вокруг доступов. А если он утёк, то он не лучше чем указатель: тот же ресурс может в этот момент модифицировать другой поток и т.п.

  • @alex_s_ciframi
    @alex_s_ciframi 2 года назад +1

    1:02:59 - для тех, кто не нашёл доклад, я вот нашёл ) ruclips.net/video/JfmTagWcqoE/видео.html

  • @jollu8
    @jollu8 2 года назад

    Самая забаная концовка )

  • @timurtsotniashvili2311
    @timurtsotniashvili2311 3 года назад

    Страница 36 (1:07:22) Почему же тогда vector::top возвращает ссылку на T, а не просто T? Ведь если мы предоставляем интерфейс с ссылкой на T&, то в некоторой степени мы сами способствуем сомнительному использованию нашего метода как в примере: const auto& x = v.top();

    • @tilir
      @tilir  3 года назад

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

    • @timurtsotniashvili2311
      @timurtsotniashvili2311 3 года назад +1

      @@tilir спасибо за ответ и спасибо за очень интересные лекции!

  • @XCemaXX
    @XCemaXX Год назад

    По поводу 55-60 минут. Для того, чтобы сделать pimpl с unique_ptr не нужно писать кастомный делетер. Достаточно написать:
    ##########.h
    struct MyClass {
    public:
    ~MyClass();
    private:
    class pImpl;
    const unique_ptr impl;
    };
    #######.cpp
    MyClass::~MyClass() = default;

    • @tilir
      @tilir  Год назад

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

    • @XCemaXX
      @XCemaXX Год назад

      ​@@tilir Хоть я и привел этот пример, но после лекции он выглядит для меня, как некая "магия") Не могли бы Вы объяснить, почему это работает? Т.е. почему прототип деструктора для класса позволяет компилятору создать unique_ptr на неполный тип?

    • @tilir
      @tilir  Год назад +1

      Основная проблема unique-ptr для pimpl это то что у него в деструкторе delete требует полный тип. Если вы его врапаете то требования к деструктору уходят в деструктор враппера, а его вы как раз откладываете. Схема в целом та же что и с откладыванием через делетер, но снаружи, а не изнутри.

  • @ВячеславШляга
    @ВячеславШляга 2 года назад

    А что делать если нужен динамический массив с неизменяемым размером? Т.е. std::vector без capacity

    • @tilir
      @tilir  2 года назад

      unique_ptr для массива?

  • @Николай-ы6к5ь
    @Николай-ы6к5ь 3 года назад

    А нельзя было бы просто модифицировать auto_ptr сделать его так как работает unique_ptr и не создавать дополнительный умный указатель?

    • @tilir
      @tilir  3 года назад

      И сломать все мегабайты существующего кода, закладывающиеся на копируемость auto_ptr?

    • @Николай-ы6к5ь
      @Николай-ы6к5ь 3 года назад

      @@tilir Всё равно он помечен на удаление в 17, или получается дали людям время на исправления.

    • @tilir
      @tilir  3 года назад

      Да, конечно

  • @namydna78
    @namydna78 Месяц назад

    Слйд 29, ruclips.net/video/JrWl5INQybE/видео.html
    Разве нельзя использовать вместо unique_ptr c; unique_ptr c; ?
    cl и gcc8 позволили.