Лекция 1. Нововведения стандарта C++11

แชร์
ฝัง
  • เผยแพร่เมื่อ 26 ธ.ค. 2024

ความคิดเห็น • 60

  • @evgenytoropov8134
    @evgenytoropov8134 5 ปีที่แล้ว +19

    Отличная лекция. Посмотрел и еще потом пересмотрю

  • @Andyy538
    @Andyy538 5 ปีที่แล้ว +12

    Спасибо, что делитесь! Интересно послушать настоящих практиков о их понимании С++.

  • @alex_nevskiy_888
    @alex_nevskiy_888 4 ปีที่แล้ว +3

    Довольно качественная лекция, и качественно сделанный для понимания ролик.

  • @ozimandias1738
    @ozimandias1738 ปีที่แล้ว

    Офигенные лекции. Совершенно случайно нашел, гуглив метапрограммирование)

  • @Avenir-Sigrun
    @Avenir-Sigrun ปีที่แล้ว +1

    огромное пасибо, Филипп.👍

  • @user-wu3vd7dd2r
    @user-wu3vd7dd2r 5 ปีที่แล้ว +1

    огромное пасибо, Филипп. клевая лекция

  • @KIR_Engineer
    @KIR_Engineer 3 ปีที่แล้ว +1

    Топовая лекция! Спасибо!

  • @Scherbakov
    @Scherbakov 3 ปีที่แล้ว +1

    Спасибо! Отличная лекция!

  • @proalex111
    @proalex111 3 ปีที่แล้ว +1

    Спасибо, человечище!

  • @kpanat
    @kpanat ปีที่แล้ว

    С перемещениями могут быть проблемы...например вы пишете такой код:
    {
    constexpr size_t SZ = 100;
    int arr[SZ];
    FillArray(1, 500, arr, SZ, true);
    Vector vec(arr, SZ);
    }
    Во второй строке массив заполняется что не играет роли. Ошибка в 4-ой строке. У шаблона Vector есть конструктор перемещения. Он берёт и указатель на int взаимствует присваивая ему nullptr как обычно это делается. А когда код выходит из области видимости вектора разумеется вызывается деструктор который освобождает память. и тут возникает исключение потому что память эта не из динамической памяти а из статической и по сути на стеке если нее глобальная. Это было бы если бы мы вынесли определение arr туда. Просто ошибка происходила бы при закрытии программы. Как исправить? Во первых у Vector дб ещё и обычный конструктор с копированием и таким же списком. Но в качестве аргумента надо написать не Vector(T *&&ar, const size_t sz) а Vector(соnst T *ar, const size_t sz) и если будет вызван 2-ой конструктор, то проблем не будет. Но создаст динамическую память в неё запишет значения а потом в деструкторе её освободит. внешне вызов выглядит одинаково они не различимы. и компилятор будет стабильно вызывать конструктор перемещения, а должен вызывать конструктор копирования. Из lvalue можно сделать rvalue, а вот наоборот нельзя!!! потому что у rvalue нет адреса... По крайнй мере при вызове. Но если преобразовать arr в константный указатель это заставит компилятор вызвать именно конструктор с копированием, а не перемещением. И проблема будет решена. А как по другому я не знаю...

  • @socketam4524
    @socketam4524 5 ปีที่แล้ว +7

    Хорошие лекции, спасиб.
    Единственная просьба - хватит проталкивать)

  • @RomanTrufanov
    @RomanTrufanov 4 ปีที่แล้ว +1

    Спасибо! Это круто!

  • @АлексейПлотник
    @АлексейПлотник 5 ปีที่แล้ว +2

    Больше всего понравилось то, что спикер похож на Тесака. Доклад тоже хороший.

    • @riz1_k
      @riz1_k ปีที่แล้ว

      Я не один кто также подумал
      XD

  • @5111
    @5111 3 ปีที่แล้ว +4

    топовый чел

  • @nocs13
    @nocs13 5 ปีที่แล้ว +11

    А не странно то что ядро большенство перечистлених программ написан на чистом C.
    почему все написанное на С пречистлается к С++... не честно же... протесту...

  • @Эрдан-з5ч
    @Эрдан-з5ч 2 ปีที่แล้ว +1

    круто 👍

  • @Dmitriy12397
    @Dmitriy12397 3 ปีที่แล้ว +1

    57:32 опечатки в коде?

  • @kirchann
    @kirchann 5 ปีที่แล้ว +2

    48:45.
    У меня не удалось воспроизвести проблему :(

    • @PVSStudioTool
      @PVSStudioTool  5 ปีที่แล้ว +5

      Давайте разбираться в этом. Нас интересует вот этот пункт стандарта: eel.is/c++draft/class.temporary#6.4
      Если вкратце, то если мы захватываем ссылку на поле временного объекта, доставая его через оператор "точка", то ссылка продлевает время жизни как временного объекта, так и вектора, поэтому все хорошо.
      godbolt.org/z/NSz6s7
      Но если мы захватываем ссылку, которая возвращает функция (ссылка на поле класса), то тут уже "ква" - ловим Undefined Behavior.
      godbolt.org/z/QHzmoj
      Спасибо, что заметили, в лекциях поправим это место :)

  • @MrTruth2
    @MrTruth2 3 หลายเดือนก่อน

    Разве Яндекс браузер не тот же хром ?

  • @КонстантинКочев-ш4э
    @КонстантинКочев-ш4э 5 ปีที่แล้ว +2

    Почему в С++ отказались от инициализации полей структур по именам полей? В простом С очень удобно. Т.е. struct rect textRect = { .Left = 0, .Top = 0, .Width = 320, .Height = 100 } в простом C возможно, а в плюсах нет.

    • @PVSStudioTool
      @PVSStudioTool  5 ปีที่แล้ว +2

      В C++20 таки подвезли: en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers
      Однако есть небольшое ограничение в отличие от языка C - инициализаторы полей должны идти в том же порядке, в котором объявлены поля. Почему именно так? Ответ прост - конструкторы: то, в каком порядке создаются поля классов, отличается в этих языках.
      Подробнее здесь - en.cppreference.com/w/cpp/language/initializer_list#Initialization_order.

  • @Simo_IT_channel
    @Simo_IT_channel ปีที่แล้ว

    PVS studio объясните пожалуйста вот такой момент, про создании лямбды и указании ввиде списка захвата & как именно будет формироваться класс на уровне компилятора, тоесть как он в поля запихнет все что есть снаружи?

    • @PVSStudioTool
      @PVSStudioTool  ปีที่แล้ว +1

      th-cam.com/video/VE3go7qcG04/w-d-xo.htmlsi=zd7HzYkWv_BeupdA&t=2023
      Вы опередили своим вопросом нас)

  • @sashabroslavskiy7904
    @sashabroslavskiy7904 2 ปีที่แล้ว +1

    Божественно.

  • @АннаКонева-ц4с
    @АннаКонева-ц4с 4 ปีที่แล้ว +1

    А можно написать, как называется проблема со скобками - most что-то там...? Не расслышала...

  • @kpanat
    @kpanat ปีที่แล้ว

    я имею ввиду rfor. Нет не по любой коллекции, по массиву нельзя если в данном месте компилятор не знает его размера. Например при передаче его в функцию через указатель. Так же по динамическому массиву нельзя... Но если написать например int *arr[]{1, 2, 3, 10, -5};(в с++20 так можно) то rfor работает. Потому что тут компилятор знает его размер на этапе компиляции. И да, этот указатель можно мувить в отличие от указателя на статическую память. Хорошо ведь правда? Вот...

  • @theK0sh
    @theK0sh 5 ปีที่แล้ว +1

    Для примера на 16:24 разве не достаточно вынести создание объекта std::pair за цикл, а в цикле уже присваивать второй паре значение i и этот объект дальше передавать в вектор. Наивная, но эффективная оптимизация..

    • @PVSStudioTool
      @PVSStudioTool  5 ปีที่แล้ว

      В целом, да, для этого примера такую оптимизацию можно сделать. При этом на каждой итерации будет вызываться конструктор копирования std::pair, что вызовет конструктор копирования MyString.
      Однако цимес данного примера в том, что до C++11 если в функцию передавали временный объект как фактический аргумент, а формальный аргумент являлся ссылкой на константу, то компилятор с этим не мог ничего поделать, и производил копирование временного объекта, что "дорого".
      Собственно, этот хитрый "бенчмарк" для этого и предназначен (на самом деле надо было в примере передавать не одну и ту же строку в конструктор пары).
      Проблема была очень насущной, и приходилось использовать разные ухищрения для устранения ненужного копирования, например COW (Copy on Write) - в строчку добавляли счетчик ссылок, и при копировании строки производилось его увеличение, в деструкторе - уменьшение. Если строчку каким-либо образом меняли, то создавался новый экземпляр строки, счетчик для новой строки приравнивался единице. Как счетчик ссылок равнялся нулю - динамически аллоцированную строчку прибивали.

  • @RedJerick
    @RedJerick 5 ปีที่แล้ว +1

    На 58:00 непонятно, разве компилятор не должен сгенерировать за нас конструкторы и операторы присваивания по умолчанию, то есть мы просто можем опустить объявление этих конструкторов? И зачем тогда default...

    • @Playerzed
      @Playerzed 5 ปีที่แล้ว +7

      Если определить какой-нибудь конструктор вручную, то конструктор по умолчанию, простите за тавтологию, не генерируется по умолчанию. Чтобы указать что его все равно нужно сгенерировать, нужен будет default.

  • @earthnews7724
    @earthnews7724 2 ปีที่แล้ว +1

    Спасибо за лекции, но я понял 5% )))

    • @PVSStudioTool
      @PVSStudioTool  2 ปีที่แล้ว

      5% это хорошее начало )

  • @Dmi3S
    @Dmi3S 5 ปีที่แล้ว +1

    Формально среди умных указателей есть еще и std::exception_ptr.

  • @uss3ewa
    @uss3ewa 2 ปีที่แล้ว

    1:40:05 а можно уточнить про что это?

    • @PVSStudioTool
      @PVSStudioTool  2 ปีที่แล้ว

      Речь идёт о spaceship operator (en.cppreference.com/w/cpp/language/default_comparisons#Defaulted_three-way_comparison). Более подробно останавливались на нём в лекции 12 (th-cam.com/video/KPuYn_fUdxc/w-d-xo.html&ab_channel=PVS-StudioRu). Если коротко - теперь можно написать следующий код:
      struct SomeStruct
      {
      int n; std::string s; float d;
      auto operator(const SomeStruct &) const = default;
      };
      А всё :) Теперь компилятор сможет за вас сгенерировать тела всех операторов сравнения. Кода стало заметно меньше. Если требуется более сложная кастомная логика - просто пишем свою имплементацию.

  • @vd3400
    @vd3400 ปีที่แล้ว

    лайк

  • @sergeyvlasov207
    @sergeyvlasov207 2 ปีที่แล้ว

    49:37 std::greater ?

    • @PVSStudioTool
      @PVSStudioTool  2 ปีที่แล้ว +1

      Да, в том примере для сортировки по убыванию действительно можно воспользоваться функциональным объектом "std::greater", даже до C++11. Однако если потребуется более сложная логика, до C++11 пришлось бы реализовывать кастомный класс с перегруженным "operator()". Скорее всего, вы бы не хотели, чтобы этот класс был виден снаружи вашей функции, т.е. класс бы пришлось делать локальным. C++11 добавил анонимные функции, которые делают все то же самое за вас.
      Если копнуть еще глубже, то лямбды имеют преимущество над локальными классами. Например, у последних имеется вот такой список ограничений (en.cppreference.com/w/cpp/language/class#Local_classes). Наиболее существенный из них - невозможность определять внутри класса шаблоны. Обобщенные лямбды из C++14 не имеют такого недостатка, и можно смело использовать (godbolt.org/z/rfbErEYxE) ключевое слово "auto" при объявлении формальных параметров. Объявление хотя бы одного такого формального параметра делает перегруженный оператор внутри лямбды шаблоном.

    • @sergeyvlasov207
      @sergeyvlasov207 2 ปีที่แล้ว +1

      @@PVSStudioTool Спасибо что потратили время и дали очень развернутый ответ :)

    • @PVSStudioTool
      @PVSStudioTool  2 ปีที่แล้ว

      @@sergeyvlasov207 Спасибо, что смотрите наши видео)

  • @vladimirmedvedev9222
    @vladimirmedvedev9222 5 ปีที่แล้ว +8

    Стандарт плюсов неисчерпаем,
    матчасть учите, кто не глуп -
    и будет вам тогда и страус,
    и труп.

    • @byte_machine
      @byte_machine 3 ปีที่แล้ว +1

      Его пример другим наука,
      Когда он начал прозревать,
      Стандарт открыл, чертей всех вспомнил,
      И мать.

  • @РайанКупер-э4о
    @РайанКупер-э4о 3 ปีที่แล้ว +1

    Стой, а до 11го лямбд не было?

    • @PVSStudioTool
      @PVSStudioTool  3 ปีที่แล้ว

      Были функциональные объекты (предикаты), но это всё нужно было делать руками... Только с 11-тых пришли нормальные лямбды (((

  • @int32h60
    @int32h60 3 ปีที่แล้ว

    откуда он знает что было изменено в 20 стандарте, если видео выпущено 1 окт 2019, а c++20 в декабре 2020?

    • @creepymuffin2351
      @creepymuffin2351 3 ปีที่แล้ว +1

      Я так понимаю все благодаря boost библиотекам, либо благодаря ранним официальным анонсам || инсайдерской инфе. Что-то вроде того, когда все за полгода до выхода уже знают дизайн следующего айфона)

  • @AlexSmile-y2x
    @AlexSmile-y2x 10 หลายเดือนก่อน

    JVM на С пишется а не на С++, жеж))

  • @kpanat
    @kpanat ปีที่แล้ว

    Ну мы же понимаем, что выражение TimeKeeper time_keeper(Timer()); не есть определение функции которая возвращает TimeKeeper и принимает на входе другую функцию возвращающую Timer и не принимающую никаких аргументов. Т.е. по сути Timer(*fun)() или TimeKeeper time_keeper(Timer(*fun)()) для пущей убедительности. Вот щаз она точно выглядит как декларация функции с именем time_keeper. Но у этой функции нет метода get_time. У функции я должен сказать вообще нет никаких методов в отличие от TimeKeeper у которого такой метод есть. Вот на это компилятор и ругается. Чего вы там совсем ку-ку вызываете метод у функции? К слову сказать у функционального объекта могут быть методы и поля, а у просто функции нет... Но мы-то вовсе не это хотели написать а определение экземпляра класса TimeKeeper с инициаллизацией которая описана в его конструкторе. Но как это объяснить компилятору если у него в приоритете функциональный подход а потом классовый. Хотя тов Ленин учил, что ко всему нужен классовый подход. И если бы компилятор так сделал как учил наш великий учитель тов Ленин то компилятор бы не запутался в 3-х соснах а сделал бы всё правильно... А не решил что это какая-то непонятная ХРЕНЬ и потом начал на эту ХРЕНЬ ругаться, которой там даже не предполагалось. О как! Ну не всё хорошо делает компилятор, но они над этим работают и пытаются устранить... Пока 23-ая версия пошла. Модули я ещё не пробовал. Но на паскале писал когда-то... Там всё примерно так как сказано в описании. Впрочем я это сразу заметил. на Фортране тоже модули.. И на Питоне с перлом. И только на плюсах хэдера. В связи с этим вопрос, а как dll писать? Ведь там это принципиально важно. И не только там... Если нет хэдеров то как же тогда? Или сделают ещё один формат выполняемых, подключаемых файлов? В паскале это TPU блин... 1994 год глубокое средневековье, а там модули!!! Я всегда говорил, что всё новое это просто хорошо забытое старое. Мы ходим по кругу... Ничего принципиально нового не выдаём... Всё где-то когда-то как-то было.

    • @PVSStudioTool
      @PVSStudioTool  ปีที่แล้ว

      Ну мы же понимаем, что выражение TimeKeeper time_keeper(Timer()); не есть определение функции которая возвращает TimeKeeper и принимает на входе другую функцию возвращающую Timer и не принимающую никаких аргументов.
      Это человек понимает семантически, что здесь декларируется объект, потому что это было его желание. А вот стандарт C++, по которому реализованы компиляторы, здесь не согласен. И дело в тяжком наследии C. C++ исторически создавался как расширение C, поэтому грамматика была переиспользована. И к сожалению, по стандарту здесь предпочитается грамматическое правило по разбору декларации функции, поскольку не встретилось ничего, что могло бы остановить парсинг согласно этому правилу.
      Вы можете попробовать изменить это, отправив предложение в стандарт:
      stdcpp.ru/proposals
      Но успеха здесь ждать не стоит. Ведь C++ развивается с ориентацией на обратную совместимость с языком C. Только создавать другой диалект C++, как например этим занимается Герб Саттер (C++2):
      github.com/hsutter/cppfront

    • @PVSStudioTool
      @PVSStudioTool  ปีที่แล้ว

      В связи с этим вопрос, а как dll писать?
      Примерно так же, как и раньше :) Итоговое приложение или динамическая библиотека получается после линкера. Здесь ничего не поменяли. Изменили этап компиляции с применением модулей. Модуль состоит из интерфейсного файла и имплементации. Когда модуль компилируется, компилятор формирует 2 файла: обычный объектный файл для линковки и BMI (Binary Module Interface). Первый всё также передается линкеру, а вот второй использует компилятор, когда встречает import в компилируемом файле. Т.к. модуль не меняется из-за внешних макроопределений (в отличие от заголовочных файлов), это позволяет сериализовать некоторое промежуточное представление в BMI и десериализовывать его, не тратя время на повторный разбор кода.

  • @xbevice
    @xbevice 5 ปีที่แล้ว +4

    90% из всего перечисленного писано на С без плюсов.

  • @Blow_BacK
    @Blow_BacK ปีที่แล้ว

    вроде на си писать умею, но из того что говорит этот дядька не имеет смысла ничего. насколько же я тупой((

    • @PVSStudioTool
      @PVSStudioTool  ปีที่แล้ว

      Вовсе нет, но теперь вы стали чуть более образованным)