Магистерский курс C++ (МФТИ, 2022-2023). Лекция 17. Умные указатели.

Поделиться
HTML-код
  • Опубликовано: 3 окт 2024

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

  • @allcreater_
    @allcreater_ Год назад +4

    Огромное спасибо за лекцию, все, как всегда, прекрасно и супер-познавательно!
    Только в 1:08:00 , кажется, небольшая неточность. У shared_ptr и так есть неявные конструкторы из shared_ptr, так что по сути они совсем ковариантны, как и обычные указатели, а вот static_pointer_cast (ну и dynamic) нужен для преобразования вниз по иерархии.
    Так что вторая строка может выглядеть так: std::shared_ptr a = b;

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

      Ого, это тонкое наблюдение, спасибо. Я проверю и если что обновлю в errata.

  • @normanmaddyson8408
    @normanmaddyson8408 Год назад +5

    27:00
    Не уверен, но предположу: в случае implicit move нужно куда-то сохранить адрес изначального объекта, для которого в конце вызывать move ctor, чтобы освободить регистры для вызова append (так как компилятор не знает, что append вернет то же самое). А в случае явного move можно его перезатереть, так как возвращать все равно будем то, что вернет append

  • @IgorPolozov-uu5fn
    @IgorPolozov-uu5fn 2 месяца назад

    Главнаый мотив не создавать в деструкторе что-либо, требование для создаваемого объекта быть noexept. В остальном, всё должно быть нормально.

  • @ddvamp
    @ddvamp 3 месяца назад +1

    52:40 Несколько интересно, что можно хранить указатель никак не связанный с подконтрольным, а также в принципе не обладать каким-либо объектом:
    struct S {};
    S obj;
    std::shared_ptr s(std::shared_ptr{}, &obj); // хранит адрес obj не владея им
    И оказывается weak_ptr тоже хранит указатель, сохраняя алиасинг

    • @tilir
      @tilir  2 месяца назад

      Интересная техника!

  • @ИванПетров-м4т2г
    @ИванПетров-м4т2г 4 месяца назад

    1:23:00
    Почему в интрузивном счётчике не нужно его делать атомарным?

  • @DmitryKandiner
    @DmitryKandiner 3 месяца назад +1

    1:29:35
    За что Херб Саттер ни возьмётся
    Всё превращается в ничто
    А если он за void берётся
    То просто тратит меньше сил.

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

    43:25 std::foo

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

    Здравствуйте, спасибо за лекцию. Возможно, на 1:21:10 имелся в виду shared_ptr как тривиальная cow строка?

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

      Да, уже заметили в комментариях.

  • @danielkeehl7450
    @danielkeehl7450 7 месяцев назад

    34:51
    Я правильно понял, что здесь имеется ввиду обычное CRTP со специализированным шаблоном?

  • @ddvamp
    @ddvamp 3 месяца назад

    7:55 Внезапно понял окончательно, почему повсеместно в стандарте в шаблонном коде используется формат direct-initialization против list-initialization
    Ну подумаешь, отдаётся приоритет list конструкторам, так здесь же объект инициализируется таким же объектом, копирование на лицо. А потом приходит человек с таким классом
    struct S {
    S() = default;
    S(S const &) { std::cout

    • @tilir
      @tilir  2 месяца назад

      Да, это интересный пример. У меня была лекция про инициализацию в углублённом курсе, надо было бы его туда добавить.

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

    26:52 получается мы возвращяем совершенно разные вещи (объект в первом случае и результат вызова append во втором)

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

      Я же объяснил словами: у нас есть внутреннее знание что append возвращает *this.

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

      Прошу прощения за это, действительно пример не для детей.

  • @Денис-ь8ь7с
    @Денис-ь8ь7с 6 месяцев назад

    Не понял, как мы без наследования (EMBCO), через включение добились оптимизации по памяти? 37:20
    Как может поле класса занимать 0 байт? Или я вообще неверно понял концепцию, подскажите, пожалуйста.

    • @tilir
      @tilir  6 месяцев назад

      Поле и не занимает 0. Оно занимает размер указателя т.к. кортеж из указателя и stateless класса как раз внутри оптимизирован через EBCO.

    • @Денис-ь8ь7с
      @Денис-ь8ь7с 6 месяцев назад

      @@tilir спасибо, понял. Это я что-то вообще неверно разглядел сначала.

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

    Как вы относитесь к подходу использования сырых указателей, как "невладеющих"? Когда проблема владения и безопасности исключения решена unique_ptr'ом, проблема вызова delete - договоронностью внутри проекта, а вопрос лайфтайма не стоит (например класс-юзер всегда создаётся после класса-владельца, и умирает раньше него)? Часто вижу такое в чужих кодовых базах, где это решения принято "осознанно", а не из-за легаси.
    В дополнение к предыдущему: Есть ли случаи, когда ссылка на unique_ptr это не "кишки наружу" и не гадость?
    Ещё видел что люди передают в функции и алиасят shared_ptr'ы через константные ссылки, чтобы попусту не пересчитывать референсы в однопоточном контексте. Что по этому поводу думаете?
    Что можно почитать на тему непосредственно проектирования с использованием умных указателей, чтобы программа не превращалась в shared_ptr-фест?

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

      Очень часто сырые указатели как невладеющие просто неизбежны. Но обычно их стараются заинкапсулировать чтобы они всё равно наружу не торчали.
      Ссылка на unique_ptr это из общих соображений сомнительная техника, но если у вас есть конкретные соображения, они всегда кроют соображения общие. Я лично примеров уместного использования unique_ptr& не знаю, но их не может не быть.
      "Что почитать на тему проектирования " это чаще всего крик в пустоту. Вот и в вашем случае мне такого не попадалось.

  • @МаксимПискун-и9з

    36:55 Размер пары почему-то равен 2 байтам, а не 1. Можете пояснить этот момент?
    #include
    struct A {};
    struct B {};
    int main()
    {
    A a;
    B b;
    using namespace std;
    pair p;
    cout

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

      Это интересное наблюдение. Действительно для std::tuple работает, для std::pair нет, причём и libstdc++ и libc++
      std::pair p;
      std::tuple t;
      std::cout

    • @ddvamp
      @ddvamp 3 месяца назад

      @@tilir Константин, а как вы предполагали это оптимизировать для pair? До С++20 не было [[no_unique_address]], так что кроме как через наследование, когда оно допустимо, разместить объекты по одному адресу не получится. А в pair они должны быть именованы как first/second

  • @Денис-ь8ь7с
    @Денис-ь8ь7с 6 месяцев назад

    Не раскрыт момент, почему make_unique не работает с кастомным удалителем 37:58. Технически разве это не сделать? Насколько я понял - концептуальное противоречие с тем, что кастомный удалитель подразумевает кастомное же и создание, а его как раз и не сделать в make_unique по определению.

    • @tilir
      @tilir  6 месяцев назад

      Я как раз и надеюсь что любой человек попробует это воспроизвести в голове а то и написать свою перегрузку make_unique с удалителем и сам осознает проблему. Там буквально два простых логических шага и вы их уже сделали.

    • @Денис-ь8ь7с
      @Денис-ь8ь7с 6 месяцев назад

      @@tilir мой мысленный эксперимент сходу не привел меня к «тупику» и я, признаюсь, нашел чужой ответ про кастомное создание, и тогда картинка сложилась. То есть получается, кастомный удалитель нужен только тогда, когда мы имеем дело с указателем на что-то «непонятное» (не класс)? Иначе мы бы пользовались конструктором и деструктором класса.

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

    По моему на трансляции эха не было...

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

      Это не эхо, это по задумке стереозвук =)

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

    В стандарт предлагали std::retain_ptr. Впрочем, не взлетело, и автор в 2021 году все это дело забросил.

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

      Об этом не слышал. Как я понимаю вот это: github.com/bruxisma/retain-ptr
      А в чём если коротко была идея?

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

      @@tilir да, это оно. Перенос интрузивного указателя из Boost в стандарт с некоторой работой над ошибками -- например, вместо free functions предлагаются трейты. Подробнее можно посмотреть в P0468, ссылка в README в репозитории.

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

      @@tilir и да, спасибо за отличную лекцию :)

  • @sigasigasiga
    @sigasigasiga Год назад +3

    1:20:41 кажется, у вас тут опечатка на слайде. разве не shared_ptr?

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

      Да, совершенно точно, спасибо. Это явно в errata.

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

    1:18:12 а точно ли это прям правильная картинка? разве weak_ptr не должен хранить внутри себя указатель на данные? ведь он же не всегда может его вытащить из контрольного блока, ибо может быть сконструирован от алиасного shared_ptr

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

      Когда я говорю о верной картинке я говорю о том что нарисовал в контрольном блоке всё что там есть. Так-то если расписывать устройство самих указателей, можно ещё много что нарисовать.