Базовый курс C++ (MIPT, ILab). Lecture 4. Инициализация и копирование.

Поділитися
Вставка
  • Опубліковано 21 вер 2024

КОМЕНТАРІ • 91

  • @alexkormilitsyn4773
    @alexkormilitsyn4773 2 роки тому +27

    Примите мои искренние благодарности за Ваш курс лекций. Слушаю сам и рекомендую сотрудникам.

  • @lonchakovav
    @lonchakovav 7 місяців тому +5

    Я программист-любитель - люблю С++ :) От ваших лекций и тонкого юмора испытываю эстетическое удовольствие. Спасибо, что выложили лекции в общий доступ.

  • @АлександрБарановский-б9з

    посмотрев лекцию, я понял как же много я не знаю . Спасибо вам, что вы делитесь знаниями.

  • @The604FX
    @The604FX Рік тому +6

    Изучаю по вашим лекциям C++, спасибо огромное за ваш труд.
    Ваши лекции - золото!

  • @pavelrid
    @pavelrid 3 роки тому +12

    Спасибо за лекцию, очень интересно.

  • @alexeylevchenko4904
    @alexeylevchenko4904 3 роки тому +5

    Константин, спасибо за труд!

  • @steinkjer27
    @steinkjer27 3 роки тому +6

    Урааа, новая серия :)

  • @enikeev_tg
    @enikeev_tg 11 місяців тому +2

    31:33
    Где-то читал, что порядок инициализации соответствует порядку объявления класса, чтобы деструктор удалял поля в обратном конструированию порядке

  • @ИскандерДобровольский-м7ч

    Вот бы послушать тот самый "первый курс", на который постоянно делаются отсылки)

    • @АмиранМстоян-ц6л
      @АмиранМстоян-ц6л Рік тому

      Присоединяюсь!
      Константин Игоревич, может запишете как-нибудь? :)

  • @kirillandrianov953
    @kirillandrianov953 2 місяці тому +1

    добрый день,
    31:05
    если дать пользователю разный порядок инициализации, то порядок разрушения должен ему соответствовать (быть обратным созданию)
    так как деструктор один, а конструкторов много, надо было бы выбрать какой порядок инициализации главный, либо сказать что он должен быть везде один. каждый из вариантов ведёт к каким-то сложностям, проще зарубить "на корню" такую возможность.

    • @tilir
      @tilir  2 місяці тому

      Звучит разумно!

  • @dsorvq
    @dsorvq 3 місяці тому

    Здравствуйте! На 34:08 говорится, что мы можем делегировать конструктор и продолжить список инициализации, при условии, что вызываемый конструктор стоит на первом месте.
    Однако, код со слайда не компилируется (второй конструктор некорректный). Вот что написано в cppreference:
    If the name of the class itself appears as class-or-identifier in the member initializer list, then the list must consist of that one member initializer only;
    Как я понимаю, лучшее, что мы можем сделать - это "немного развернуть делегирование" и из конструктора с меньшим числом аргументов, вызывать конструктор с большим их числом.

    • @tilir
      @tilir  2 місяці тому

      Странно что ещё не было в errata, вроде это тут уже находили. Добавил, спасибо.

  • @ОлегВасилевский-ш8щ

    Здравствуйте! Спасибо за ваш труд, каждую лекцию жду как любимый сериал. Попробовал в godbolt пример про copy-init 1:19:45 . В clang и gcc10 компилирует как у вас в примере. В gcc11 в обоих случаях вставляет "Bar::operator Foo()", в msvc в обоих случаях "Foo::Foo(Bar const &)". Пути компилятора неисповедимы :) За ссылку на godbolt ютуб блокирует комментарии

    • @tilir
      @tilir  3 роки тому +1

      Очень интересное наблюдение. Надо проверить по стандарту кто прав ))

    • @nikolayivanov2827
      @nikolayivanov2827 Рік тому

      Да. Поэкспериментировал на GCC.
      До 17-го стандарта без explicit на operator Foo() имеем
      Ctor Bar -> Foo
      Op Bar -> Foo
      После 17-го стандарта без explicit на оператор Foo() имеем
      Op Bar -> Foo
      Op Bar -> Foo
      До 17-го стандарта с explicit на operator Foo() имеем
      Ctor Bar -> Foo
      Ctor Bar -> Foo
      После 17-го стандарта с explicit на operator Foo() имеем
      Op Bar -> Foo
      Ctor Bar -> Foo.
      Симметричненько получилось. Судя по всему, начиная с 17го стандарта, операторы приведения (явные и неявные) снаружи в "нас" попадают в преимущественные позиции списка перегрузок direct-инициализации для объекта типа "нас". Но и до, и после, direct-инициализации всё ещё пофиг на explicit, а copy -- нет.
      Это только в контексте GCC. На других не пробовал.

  • @ddvamp
    @ddvamp Рік тому +1

    1:19:40 Был убеждён результатами на экране, но вернулся в процессе разбора случая из лекции по исключениям. Набрав этот сниппет у себя, получил иной результат. У вас видимо по умолчанию стандарт С++14 в компиляторе? Выяснил, что при переходе на С++17 стандарт результат стал иным, и в обоих случаях вызывается оператор преобразования. Если расписать подробнее
    Bar b; // 14 17gcc 17clang
    Foo f0 (b); // ctor op op
    Foo f1 {b}; // ctor op op
    Foo f2 = {b}; // ctor ctor op // в текущем черновике инициализации f1 и f2 идентичны

    Foo f3 ({b}); // ctor ctor ctor
    Foo f4 {{b}}; // ctor ctor ctor
    Foo f5 = {{b}}; // ctor ctor ctor
    Foo f6 = b; // op op op
    На этот раз стандарт не осилил, но кажется лишь в случае copy-initialization могут рассматриваться функции преобразования. Тогда в чем же дело?
    Единственное предположение, что здесь по какой-то причине вступает в силу copy elision.
    Поиск в интернете дал вопрос на stackoverflow "Call to conversion operator instead of converting constructor in c++17 during overload resolution", где приводится ссылка на CWG243, дающую ровно ту же мотивацию, что и вы (что выглядит как вызов конструктора им и должно быть). Там же есть ссылка на Bug 82840 для gcc, где дал ответ разработчик gcc.
    Так в соответствии с P0135R1 (guaranteed copy elision) и в gcc (gcc/cp/call .cc# L12475), и в clang сделали выбор в пользу copy elision, вопреки текущему стандарту. То есть они рассматривают и функции преобразования, как в copy-initialization.
    Поискав еще немного, нашел архивные сообщения в std-discussion и CWG2327 за авторством Richard Smith, где сказано, что это в действительности упущение в стандарте (что игнорируется copy elision), и его хотят устранить.
    Фух. И как после такого писать на С++?!
    P.S. И как после такого не любить С++?🙃
    P.P.S. Но почему тогда в gcc f1 и f2 не совпадают?..

    • @user-bg2nr4sz7q
      @user-bg2nr4sz7q Рік тому

      В mingw-10.0.0 такая же фигня, если -std=c++14, с f1 вызывает конструктор, если -std=c++17, c++2a, c++2b - в обоих случаях оператор

  • @greatnews8390
    @greatnews8390 2 роки тому

    Спасибо Вам за прекрасные лекции и подачу материала. Если бы не было NRVO в вашем примере (проверьте с флагами -std=c++14 -fno-elide-constructors на gcc), то вызвалось бы два copy конструктора, а не один (в лекции не упомянули про тот, который на return).

  • @victormustya1745
    @victormustya1745 3 роки тому +5

    1:08:00 а каким образом можно сделать аргументом конструктора копирования значение? Ведь чтобы его передать как параметр, нужно вызвать конструктор копирования, у которого параметр значение, чтобы его получить надо вызвать конструктор копирования, у которого параметр значение.... Кажется, в этом месте что-то должно сломаться (-:

    • @tilir
      @tilir  3 роки тому +4

      Да, спасибо, так можно делать только у оператора присваивания. Это я что-то не подумав сказал. Внесу в еррату.

  • @allcreater_
    @allcreater_ 3 роки тому +3

    Спасибо за лекцию, присоединяюсь к мнению насчёт сериала :)
    Рискну высказать маленькое предложение чисто по визуальному оформлению: не стоит ли включить в vim подсветку синтаксиса (а то и вовсе обмазать плагинчиками)? IMHO такой код и просто легче восприниматься будет, и поаккуратнее выглядеть, и заодно послужит популяризации консольных редакторов (говорю как закоренелый пользователь VS!)

    • @tilir
      @tilir  3 роки тому +2

      Очень не люблю подсветку синтаксиса, везде её отключаю. Это личное.

    • @Robinzon__Kruzo
      @Robinzon__Kruzo 3 роки тому

      @@tilir а вы долго привыкали к голому тексту, или с самого начала без подсветки работали? Просто уже не в первый раз встречаю тезис, что подсветка не нужна. Чувствуете ли какие-то проблемы, или это просто вопрос привычки? А то тогда тоже попробую отключить подсветку.

    • @tilir
      @tilir  2 роки тому +2

      Ну я не заявляю что отсутствие подсветки лучше. Для многих может быть и правда лучше её наличие. Скорее просто с детства привычка.

  • @lilitgrigoryan9228
    @lilitgrigoryan9228 8 місяців тому

    Здравствуйте! Спасибо за лекции. На слайде 69 нет деструктора. Он там не нужен или просто не относится к теме?
    И кажется на слайде 75 маленькая опечатка. В return должен быть x_.

  • @rsynk
    @rsynk 3 роки тому +2

    👍

  • @ЛеонидСидоров-б9б
    @ЛеонидСидоров-б9б 8 місяців тому

    26:12 - проверил. Сначала direct, потом default)

  • @РадегастСварожич
    @РадегастСварожич 3 місяці тому

    Константин Игоревич, скажите, пожалуйста, в домашней работе "HWT" нужно использовать декартово дерево?

    • @tilir
      @tilir  2 місяці тому

      Да, это самый разумный выбор.

  • @siarheimarozau6763
    @siarheimarozau6763 2 роки тому +3

    На странице 59 в строке std::copy должно быть
    std::copy(rhs.p_, rhs.p_ + rhs.n_, p_);
    Конечно это просто невнимательность но никто из студунтов не заметил.

    • @tilir
      @tilir  2 роки тому

      На самом деле в errata это уже есть, значит ошибку кто-то уже нашёл, но всё равно спасибо за внимательность.

    • @dmitrydemis8981
      @dmitrydemis8981 Рік тому +1

      @@tilir Здравствуйте, Константин. Также можно использовать функцию std::copy_n(rhs.p_, rhs.n_, p_), которая немного упрощает вариант

    • @arthursilaev4368
      @arthursilaev4368 10 місяців тому

      Заметил, но авторитет Константина меня придавил. Пошел комментарии читать а тут вы, спасибо))

  • @АлексейЕлисеев-г4ю
    @АлексейЕлисеев-г4ю 2 роки тому +1

    Здравствуйте, очень хорошие лекции! Вопрос: слайд 25, почему используется десятичный, а не двоичный логарифм при оценки высоты дерева для лучшего случая.

    • @tilir
      @tilir  2 роки тому +1

      Просто опечатка, там должно было быть logN без указания конкретного основания.

  • @ext00
    @ext00 2 роки тому +2

    Не подскажете, почему explicit конструктор это экстрим? Сам Страуструп в Core Guidelines советует это делать по умолчанию, clang tidy будет вам настойчиво советовать сделать конструктор explicit, а вы утверждаете полностью противоположные вещи. По-моему, как раз неявное преобразование должно быть хорошо обосновано.

    • @tilir
      @tilir  2 роки тому

      В clang-tidy много странных чекеров, особенно в разделе modernize. Что до core guidelines, я в последний раз заглядывал туда кажется в 2016 и там рекомендовалось всюду использовать array_view. Я как-то больше не открывал.
      Я исхожу из того, что пользовательские типы должны вести себя как int и float -- в том числе конвертироваться друг в друга если это ничего не стоит. Только если конвертирование сопряжено с затратными операциями -- выделением памяти и всем таким, можно подумать (подумать!) про explicit.

    • @ext00
      @ext00 2 роки тому +1

      @@tilirАргументация против данных кодстайлов, конечно, интересная, только вот думается, что они и многие другие советуют это делать не просто так. Пользовательские типы точно не должны себя вести как int и float с точки зрения преобразований, даже если не затрагивать всю спорность таких неявных кастов. int это int, просто значение и ничего больше, пользовательский тип практически всегда сложней и конструирование при помощи значения другого типа зачастую не означает их семантическую эквивалентность. Вы говорите, что они должны(!) конвертироваться друг в друга, если это ничего не стоит. Что, даже если это приводит не к тому, чего ожидал программист? Ну а что, сам виноват, забыл что char/bool/double превратится size_t и ты получишь черт знает что. Вы опытный разработчик и, возможно, всегда держите в голове этот и миллион других нюансов языка C++, когда пишете код, но зачем вы настаиваете, чтобы неопытные разработчики оставили этот способ стрельнуть себе в ногу вдобавок ко всем остальным?

    • @tilir
      @tilir  2 роки тому +1

      Вот именно что в моём опыте неявные преобразования становятся страшными только в одном случае -- когда появляются указатели и инцидентные структуры и нарушается value-семантика. Но это уже не проблема преобразований. Пока value-семантика соблюдена, гайдлайн "вести себя как int" очень полезен. Например он мотивирует зачем ставить const на методы и т.п. И разумеется нет ничего более правильного, чем неявное преобразование int в double. Я с ужасом думаю, что в каждом таком случае пришлось бы писать static_cast.
      С другой стороны я вполне открыт к новым идеям и сильным аргументам. Если вы посоветуете хороший доклад насчёт того почему везде нужен default explicit (или сами такой запишете -- с примерами и всем таким), то это будет очень позитивно.

  • @sdgsweg
    @sdgsweg Рік тому

    Зануление указателей в деструкторе удобно в том случае, если мы случайно обратились к уделенному объекту. Если это произошло через короткое время, то память объекта не успевает распределиться на другой объект и такое обращение вызывает мгновенный Access Violation. Т.е. нам не потребуется сложного дебага. Правда современные компиляторы делают что-то подобное за нас.

    • @tilir
      @tilir  Рік тому +1

      Если вы случайно обратились к удаленному объекту это ub и последствия непредсказуемы. Вас ничего не спасёт.

    • @sdgsweg
      @sdgsweg Рік тому

      @@tilir понятно что гарантий 100% никто не дает, но это повышает шансы того, что ошибка проявиться скорее раньше чем позже. Создайте дебаг проект на Visual Studio, создайте переменную инициализированную нулями с помощью new (например long long) вызывайте delete и смотрите что на самом деле окажется в переменной. Вся переменная будет заполнена байтами 238 / 254. Это происходит строго в функции delete и это документированное поведение для debug сборок на Visual Studio. Это делается намеренно для облегчения отладки. Более того есть ключ _CRTDBG_DELAY_FREE_MEM_DF , как можно понять из названия, куча даже придержит освобожденные блоки, чтоб дать дополнительный шанс выстрелить такому заполненному блоку.

    • @tilir
      @tilir  Рік тому

      Зануление после delete в линейном участке кода имеет смысл (хотя сам по себе delete в линейном участке это скорее всего ошибка проектирования). Зануление в деструкторе не имеет смысла. Никаких шансов оно не повышает, я на лекции показывал ассемблер.

  • @tommorfin3499
    @tommorfin3499 Рік тому

    Спасибо за лекции!
    На 26:10 Вы говорите, что выведется сначала "default", потом "direct", это видимо оговорка? В теле конструктора `key_ = key` вызовет ведь оператор присваивания

    • @tilir
      @tilir  Рік тому

      Нет это не оговорка, это именно direct-инициализация, а не копирование. Та есть ссылочка на слайдах, щёлкните по ней.

    • @tommorfin3499
      @tommorfin3499 Рік тому

      ​@@tilir Но там ведь direct-инициализация выполняется, чтобы привести `KeyT` к `S`, который ожидает оператор присваивания в качестве правой части. В `key_` новое значение именно присваивается же?

    • @tilir
      @tilir  Рік тому

      @@tommorfin3499 да согласен. Это direct инициализация а ПОТОМ копирование. Действительно можно такое уточнять.

  • @dmitry6123
    @dmitry6123 3 роки тому +1

    31:05 Ответ очевиден же. В деструкторе переменные класса разрушаются в обратном порядке объявления, поэтому для соблюдения детерминизма пользовательские перестановки в конструкторе явно запрещены.

    • @tilir
      @tilir  3 роки тому

      Интересный аргумент, спасибо. Мне, правда не очень очевидно почему обратный порядок в деструкторе что то значит если пользователь хочет явный список инициализации. Допустим его устраивает такого рода ассимметрия...

    • @evgenytarasov2541
      @evgenytarasov2541 2 роки тому +1

      @@tilir IMHO. Думается, тогда бы сильно запутались вопросы, связанные с нормативным проектированием классов относительно безопасности исключений? В особенности когда зависимые друг от друга участники списка инициализации деконструировались в обратном порядке их членства, а не списка (а например другие члены класса вообще не были бы упомянуты в списке инициализации). (Для пользователя нет проблем с простой асимметрией в простом случае, но как быть с гарантиями языка в общем случае). Понятно что вопросы исключений появились потом, но это ничего не меняет для интуиции.

    • @ИгорьПорошин-л6м
      @ИгорьПорошин-л6м 2 роки тому

      @@tilir Если мы в списке инициализации определяем порядок вызова конструкторов полей класса, то это вызовет дополнительные вопросы которые нужно будет решить, например:
      1. В классе 15 полей, а я прописываю в список инициализации только 2-а (4-й и 3-й), то не понятно с какого поля начинать вызывать конструкторы
      2. Если в списке инициализации можно будет указывать порядок вызова конструкторов, то рано или поздно кто-нибудь захочет список вызова деструкторов полей класса(список деинициализации) и вызывать его нужно будет примерно так: ~Node() {/*тело деструктора*/} : key2_.{}, key1_.{};

  • @Michael-Solo
    @Michael-Solo 3 місяці тому

    на слайдах 60 и 61 разве нет ошибки в функции копирования?
    Там же должно быть с какого указателя по какой и в какой копируем
    то есть std::copy(rhs.p_, rhs.p_ + n_, p_);

    • @tilir
      @tilir  2 місяці тому

      Спасибо, добавил в errata.

  • @kirillnikulin605
    @kirillnikulin605 2 роки тому

    Приветствую, Константин! Правильно ли я понимаю, если мы говорим о написании надежного промышленного кода, то рекурсия это или smell code, или еще консервативнее - просто неприемлемо?

    • @tilir
      @tilir  2 роки тому +1

      Здравствуйте. В целом да, сама по себе рекурсия привлекает внимание к коммиту. Но не надо быть слишком категоричным. Я видел как рекурсия проходила ревью и становилась частью промышленного кода там и тогда, где и когда это было оправдано.

  • @alexbur140
    @alexbur140 2 роки тому +1

    В С++ 11 очень полезным нововведением было explicit operator bool, для которого явный контекст определяется компилятором из if, while...
    Вопрос: имеет ли смысл в каком-либо контексте explicit operator int() или explicit operator MyType()?

    • @tilir
      @tilir  2 роки тому

      Спасибо, интересное дополнение.
      Писать explicit полезно когда вы хотите заблокировать неявные преобразования. К счастью кроме bool исключений тут не делали. Исключение для bool мне не нравится, т.к. создаёт неприятную асимметрию:
      struct S {
      explicit operator bool() { return 1; } // 1
      explicit operator int() { return 1; } // 2
      ...
      S s;
      if (s) { .... } // ошибка для 2 но не для 1
      Может быть конечно стоило бы о таком упоминать. Но с другой стороны это слишком распыляющие внимание нюансы. Можно обсудить в комментариях.

  • @KIR_Engineer
    @KIR_Engineer 6 місяців тому

    Вопросы по слайдам 59 и 60. Если используется int в качестве типа буфера, то нужна проверка на знак? Почему бы не использовать size_t для размера буфера как в stl контейнеразмерах?

    • @tilir
      @tilir  6 місяців тому +1

      Я избегаю лишнего использования беззнаковых типов т.к. операции над ними из-за отсутствия UB плохо оптимизируются. В стандартных контейнерах size_t был ошибкой проектирования, причём довольно дорогой, и, увы, засох в таком виде.
      Проверка на знак не нужна т.к. по инварианту класса там не может быть отрицательного числа.

    • @KIR_Engineer
      @KIR_Engineer 6 місяців тому

      @@tilir Спасибо за ответ!)
      На днях был разговор со старшим коллегой, который также указывал на преимущества оптимизации int по сравнению с uint. Он не настаивал на своём мнение, а я не придал должного ему значения. Впредь буду внимательнее в наших беседах. Спасибо за информацию!)
      А я всё думал - почему в protobuf тип размера контейнера int? Получается дело в оптимизации?

  • @vanyakhodor3387
    @vanyakhodor3387 2 роки тому

    По поводу объектов нулевого размера. Не очень понятно, как это ломает delete[].
    Предположим, я компилятор. Я знаю, что тип пустой (i.e. не хранит данных). Буду считать, что все объекты в массиве начинаются в одном месте. Когда нужно проитерироваться по нему, буду отдавать один и тот же указатель (данных там нет, ничего не ломаю). Когда остановиться я знаю (размер слева от массива лежит). Тут конечно возникают проблемы с реализацией end() для пользовательских типов, т.к. в терминах типа нулевого размера end() недостижим, но как будто и это программисту можно было бы обойти. Короче язык был бы ещё более страшным, но все проблемы как будто можно решать)

    • @tilir
      @tilir  2 роки тому +2

      Вы вызываете деструктор передавая туда адрес объекта. Вызвав деструктор дважды по одному адресу вы получите double free.

  • @evgenyyun8322
    @evgenyyun8322 10 місяців тому

    8:30 слайд 29 - это не поисковое дерево, насколько я понимаю, так слева от узла (2) - узел (3), а 3 > 2. Или я ошибаюсь?

    • @tilir
      @tilir  10 місяців тому

      Да совершенно точно. Я тут чего-то не то на слайд вынес. Впрочем оно достаточно плохое в плане сбалансированности чтобы демонстрировать идею.

  • @bkWorm-gx2pi
    @bkWorm-gx2pi 4 місяці тому

    На 1:06:54, что значит "sf rule", нигде не нашел, не разобрал слово

    • @tilir
      @tilir  4 місяці тому

      "as-if rule". См. лекцию по стандарту C из соотв. курса: ua-cam.com/video/WAA04Wt48dE/v-deo.html

  • @bohdankladochnyi3995
    @bohdankladochnyi3995 3 роки тому +1

    Здравствуйте. А можно ссылку на видео "as if rule" (если я правильно понял), которое вы упомянули на 1:06:58

  • @d7d1cd
    @d7d1cd 3 роки тому +1

    68 слайд.
    А если конструктор копирования написать как Copyable(const Copyable &c), он будет считаться "правильным" конструктором копирования?

    • @tilir
      @tilir  3 роки тому +1

      Да, это же константная ссылка на себя.
      [class.copy.ctor] регламентирует это так:
      non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, [...]

    • @d7d1cd
      @d7d1cd 3 роки тому

      То есть, в примере из лекции компилятор считает тип Copyable совершенно другим типом, даже если параметры шаблонов класса и его конструктора одинаковы? Зачем так сделано? Почему не научить компилятор распознавать подобное?

    • @tilir
      @tilir  2 роки тому +1

      Я полагаю так сделано из-за ленивого инстанцирования шаблонов. При шаблонном конструкторе копирования компилятор не может, глядя только на определение класса, определить нужен в итоге конструктор по умолчанию или нет т.е. будет этот конструктор инстанцирован или не будет.

  • @BARABUMBS
    @BARABUMBS 10 місяців тому

    Добрый день! Подскажите на счёт примера на 1:20:20 Попробовал повторить и получилось, что при стандарте > c++14 в обоих случаях вызывается оператор

    • @tilir
      @tilir  10 місяців тому

      Да вы правы, залипло из 11 стандарта.

  • @alex_s_ciframi
    @alex_s_ciframi 2 роки тому

    Константин, приветствую! Тут назревает (но, надеюсь, не произойдёт) блокировка ютуба. А мне хотелось бы все ваши лекции таки дослушать. Есть ли где-нибудь ещё копия лекций?

    • @tilir
      @tilir  2 роки тому +2

      Почитайте вкладку community. Там верхний пост ссылка на телеграм, а во втором-третьем на дискорд.

    • @alex_s_ciframi
      @alex_s_ciframi 2 роки тому

      @@tilir рутуб я нашёл, а дискорд - не сумел. Во втором посте только рутуб :)

    • @tilir
      @tilir  2 роки тому +1

      @@alex_s_ciframi : discord.gg/vSEp8yW

  • @ddvamp
    @ddvamp Рік тому

    Добрый вечер. Не нужно ли добавить errata относительно 43 слайда? Как я вижу, на последних выложенных слайдах это отмечено цветом.

    • @tilir
      @tilir  Рік тому

      Да на 43-м действительно ошибка. Сформулируете мне строчку для errata?

    • @ddvamp
      @ddvamp Рік тому

      @@tilir Ох, из драфта "If a mem-initializer-id designates the constructor's class, it shall be the only mem-initializer; ...Once the target constructor returns, the body of the delegating constructor is executed.", поскольку инициализация всех членов уже выполнена (целевым конструктором) конструктором делегатом. Как это выразить лаконично, я не уверен.

  • @ДмитрийСадков-е8ц
    @ДмитрийСадков-е8ц 2 роки тому

    Добрый день, Константин, допустимо ли использовать фигурные скобки в списке инициализации в конструкторе?
    Node(KeyT key) : key_{key} {}
    вместо
    Node(KeyT key) : key_(key) {}

    • @tilir
      @tilir  2 роки тому

      Да конечно и многие так и делают.

    • @ДмитрийСадков-е8ц
      @ДмитрийСадков-е8ц 2 роки тому +2

      Константин, спасибо за ответ! У меня еще вопрос по делегирующему конструктору. Я попробовал код с презентации (страница 43), немного упростив его:
      #include
      struct class_c {
      int max = 0, min = 0;
      class_c(int my_max) : max(INT_MAX) {}
      class_c(int my_max, int my_min) : class_c(my_max), min(INT_MIN) {} // Line 6
      };
      Но, он не компилируется.
      g++ -std=c++11 test.cpp
      test.cpp: In constructor ‘class_c::class_c(int, int)’:
      test.cpp:6:67: error: mem-initializer for ‘class_c::min’ follows constructor delegation
      $ clang -std=c++11 test.cpp
      test.cpp:6:39: error: an initializer for a delegating constructor must appear alone
      Компилируется только если поменять
      class_c(int my_max, int my_min) : class_c(my_max), min(INT_MIN) {}
      на такой вариант
      class_c(int my_max, int my_min) : class_c(my_max) {}
      Получается, что делегированный конструктор должен быть не первым, а единственным в списке инициализации.
      ========================
      Еще заметил неточность на страницах 56, 57:
      {Buffer x; Buffer y = x; } // double deletion
      Не получится создать объект класса Buffer через Buffer x;
      Нужно указать количество элементов выделяемого массива, например 5:
      {Buffer x{5}; Buffer y = x; } // double deletion
      ========================
      И на странице 59 "Реализуем копирование" в конце строки, перед фигурной скобкой не должно быть запятой:
      Buffer(const Buffer& rhs) : n_(rhs.n_), p_(new int[n_]), {
      Buffer(const Buffer& rhs) : n_(rhs.n_), p_(new int[n_]) {
      ========================
      Возможно ошибаюсь, но похоже на странице 73 "Пользовательские преобразования", на рисунке, перепутаны направления стрелок.

    • @tilir
      @tilir  2 роки тому +1

      Спасибо, про делегирующие конструкторы вы правильно заметили. Внесу в errata.

  • @ДенисКолчев-щ4с

    1:04:42
    Копирование? Какое копирование? Где копирование? Нет копирования. Забудьте. Не было копирования. 😂

  • @ДенисКолчев-щ4с

    42:24 я тоже так привык делать. Такой совет исходит от сайта raveslicom. Там, на всякий случай после вызова delete, рекомендовали занулять память.

    • @tilir
      @tilir  Рік тому

      Да много где это советуют. Очевидно они неправы.