Изучение C++ No.30 [борьба с лямбда-выражениями]

введение:

Пекинское время: 2023/6/9/9:13, я встал сегодня в 8:15.Возможно, в последнее время очень мало занятий, поэтому нет необходимости вести блог.Я могу писать в любое время, поэтому я не могу встать в 7 часов.Хахаха,я привыкла спать.Да,но проблема не большая,и она еще в пределах контролируемого диапазона,а буквально позавчера у нас был выпускной экзамен MySQL в школе, и я изучил MySQL на первом курсе Big, который сказал мне, что я не только блоггер CSDN, но и профессионал в просмотре CSDN, поэтому я все еще много знаю об операциях MySQL, так что если я случайно возьму первый практический вопрос, я подумаю об этом позже Я использовал все свои очки знаний, хахаха! Однако есть и плохая новость, то есть практические занятия переведены с онлайн на оффлайн, бла-бла, плакать хочется, а такая практика целый день, ух ты, это реально раздражает, в основном Наши время автономной работы компьютера не очень хорошо, эй! Не много глупостей, все зависит от человеческих усилий, в древности есть известная поговорка: от людей зависит, чтобы что-то происходило, и моя судьба зависит от меня Знания, и, наконец, введите изучение лямбда-выражений через соответствующие знания. параметров переменных шаблона! Давай, давай, давай!

вставьте сюда описание изображения

ссылка на rvalue, оставшаяся релевантным знанием

Из-за проблемы со временем в последнем блоге все еще есть очень важный момент знаний, который не был объяснен в конце, то есть следующие знания о мобильном назначении, которые мы собираемся изучить, хотя суть мобильного назначения и мобильная конструкция не сильно отличается. После освоения того, что такое мобильная структура, изучение мобильного задания похоже на толкание лодки по пути. нам необходимо проанализировать его здесь следующим образом:

Что такое мобильное задание

Точно так же, согласно вышеизложенному, основной принцип мобильного задания не сильно отличается от мобильного построения, поэтому, согласно моему старому мышлению, изучение чего-либо - это изучение через сравнение или иллюстрацию. Здесь все просто, мы будем использовать мобильное построение. чтобы сравнить мобильное задание, чтобы выяснить, что такое мобильное задание. А пока давайте повторим знания, связанные с мобильным строительством! Прежде всего, поймите, что предпосылкой построения перемещения является то, что значение является rvalue.Поскольку rvalue пользовательского типа является значением, которое не понадобится программе, оно будет уничтожено.Эффективность выполнения и оптимизированное управление ресурсами методы, он может косвенно идентифицировать rvalue через ссылки rvalue, тем самым выполняя соответствующие коды построения перемещения вместо исходных кодов построения копирования, связанных с lvalue, но обратите внимание: приведенная выше конструкция перемещения, во-первых, нацелена на пользовательские типы, а во-вторых, мы нацеливание на пользовательские типы, требующие глубокого копирования, поэтому, если соответствующий объект является встроенным типом или пользовательским типом с поверхностным копированием, то нет никакой разницы между построением перемещения и созданием копирования.

Мобильное задание для формального обучения

Поняв вышеприведенные знания, давайте поговорим об отношениях между конструкторами и операторами присваивания. На мой взгляд, оба они по существу используются для инициализации объектов, но есть определенные различия в инициализируемых объектах. Таким образом, самая большая разница между ними заключается в том, является ли Объект, который нужно присвоить, и объект, который нужно построить, определены. Если объект, который нужно инициализировать, уже существует, то в данный момент это присваивание. Как рыба в воде, точно так же нет разницы между принципом мобильного присваивание и мобильная конструкция. Он также основан на использовании rvalue (значение x) и напрямую передает ресурс, соответствующий значению x, в назначенное значение в форме присвоения. Объекты, этот метод присвоения также известен как мобильный назначение, как показано на следующем рисунке:
вставьте сюда описание изображения

注意:В настоящее время причина использования присваивания перемещения для получения возвращаемого значения функции заключается не только в использовании конструкции перемещения, но и в использовании присваивания перемещения. Причина в том, что присваивание перемещения и конструкция перемещения относятся к двум разным методам инициализации, и компилятор не будет таким же, как конструкция перемещения.Чтобы оптимизировать две конструкции перемещения в одну конструкцию перемещения, предпосылка, которую компилятор может оптимизировать, представляет собой непрерывное построение или непрерывное присваиваниевставьте сюда описание изображения
, как показано на рисунке ниже: , мы знаем, что если С хочет вернуть деньги, он должен найти В, и, наконец, вернуть деньги от А опосредованно через В, но не может найти А напрямую, потому что А вообще не знает С, а доказательств нет. , так что точно не возможно Завершить цель, так что компилятор тот же, только в случае непрерывного построения или непрерывного присваивания он может завершить оптимизацию, то есть в случае, когда С знает А, через определенные операции, цель просить денег наконец достигнута

Разница между построением перемещения и назначением перемещения

Получив вышеуказанные знания, мы можем выяснить конкретный принцип использования мобильного задания, но я полагаю, что у многих студентов все еще есть некоторые сомнения, поэтому, как очень ответственный блогер CSDN, мы должны теперь использовать мобильное задание. Для дальнейшего сравнения с построением перемещения, во-первых, хотя мы поняли самую большую разницу между конструкцией и присваиванием выше, то есть определен ли инициализируемый объект или нет, все же есть некоторая разница между конструкцией и присваиванием по сути, например: конструкция для объект, который необходимо определить. Объект обращается за ресурсами, а затем инициализирует его, а назначение заключается в непосредственном присвоении соответствующего значения объекту, который необходимо инициализировать, поэтому в соответствии с этой разницей существует разница между построением перемещения и назначением перемещения по существу, Конструкция перемещения заключается в прямом назначении. Ресурс, соответствующий значению r, передается определяемому объекту, но назначение перемещения отличается, поскольку назначенный объект уже существует до назначения перемещения, поэтому при передаче ресурса мы не только передать ресурс, соответствующий rvalue, в назначенный объект, и ресурсы, соответствующие назначенному объекту, также будут переданы rvalue, и rvalue вот-вот будет уничтожено в это время, поэтому ресурсы, соответствующие rvalue в это время , то есть ресурсы, соответствующие назначенному объекту, будут косвенно уничтожены, что еще раз повышает эффективность выполнения кода и оптимизирует метод управления ресурсами, как показано на следующем рисунке: Итак, по сути, хотя
вставьте сюда описание изображения
перемещение вызывается назначение, необходимо выполнить конструкцию перемещения еще раз, но из-за назначения перемещения оно может быть высвобождено косвенно Ресурсы, поэтому нет никакой разницы между ними с точки зрения эффективности.Следующее является наиболее существенным различием в запись между конструкцией перемещения и назначением перемещения. Аналогично, для назначения перемещения инициализированный объект — это объект, который уже был определен, в то время как конструкция перемещения предназначена для создания объекта, который определяется
вставьте сюда описание изображения

Наконец, я понимаю, что будь то мобильное построение или мобильное назначение, суть называется мобильной семантикой. Цель — оптимизировать управление ресурсами и повысить эффективность выполнения кода за счет продления жизненного цикла соответствующего rvalue. Если быть точным, это расширение соответствующий жизненный цикл ресурса

Подробное объяснение ссылки на const

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

Конкретный анализ сценариев использования константных ссылок
Будь то при изучении ссылок в вводном C++ или при изучении ссылок rvalue, мы все знаем, что ссылки можно использовать в сочетании с константами, и сценарии использования относительно часты, так почему же константы и константы должны быть используется?Что насчет комбинации ссылок? Прежде всего, давайте возьмем наш последний блог, чтобы узнать, когда ссылки lvalue могут ссылаться на rvalues.Если ссылки lvalue хотят ссылаться на rvalues, то необходимо добавить const.Суть в том, что rvalues ​​постоянны, поэтому изучите, прежде чем когда они связаны с справочные знания, такие как: при использовании ссылки в качестве параметра функции и ссылки в качестве возвращаемого значения функции, зачем вам нужно добавлять const? На самом деле, суть в том, чтобы продлить жизненный цикл соответствующего ресурса и предотвратить уничтожение соответствующего ресурса rvalue до передачи параметра, приводящее к ошибке компиляции, как показано на рисунке ниже: Как показано на рисунке выше, суть в том, что если rvalue не использует const& для получения, то
вставьте сюда описание изображения
оно будет уничтожено заранее.Суть и почему на rvalue можно ссылаться после того, как ссылка на lvalue использует const-та же причина.Суть в решении проблемы того, как получить rvalue, чтобы ресурсы rvalue не были уничтожены заранее, а затем он мог завершить соответствующую задачу построения копии или построения назначения, и его можно было бы разумно освободить только после завершения задачи, но это должно быть отметил, что не во всех местах можно использовать константные ссылки, например: при использовании константной ссылки в качестве возвращаемого значения в настоящее время это может вызвать проблемы, как показано на рисунке ниже: Поэтому, когда константа и ссылка
вставьте сюда описание изображения
используются вместе, вы должны быть осторожно, и вышеупомянутый метод использования ссылки const для возврата локальных объектов должен быть ограничен.Если вы хотите использовать ссылку const в качестве возвращаемого значения, тогда необходимо убедиться, что объект не является локальным объектом и не будет уничтожен с разрушением кадра стека, то есть объект должен быть статической переменной (static) или переменной кучи (new).Конечно, последний способ избежать этого — не , если вы не используете константу ссылка в качестве возвращаемого значения, тогда возвращаемое значение соответствующей локальной переменной будет создавать временную переменную при возврате, чтобы сохранить соответствующие данные перед разрушением и использовать их для вызывающего местоположения, все так разумно, хахаха!小知识点: В это время для фрейма стека функций, если временная переменная маленькая, она будет помещена в регистр, если она большая, то она будет помещена в верхний фрейм стека функций относительно функции (обычно основная функция )

Новые возможности классов C++11

Когда дело доходит до функций классов, первое, что приходит на ум, — это знание 6 функций-членов по умолчанию, которые мы узнали, когда изучали классы и объекты, то, что мы часто используем и о чем говорим, но эти 什么构造呀,什么析构呀,什么拷贝构造呀,什么拷贝赋值呀,什么取地址呀,什么const取地址呀6 Функция-член по умолчанию — это только содержимое в C++ 98. Начиная с C++ 11, класс добавил еще две функции-члена по умолчанию, то есть я только что узнал об этом недавно. Однако для этих двух функций, если 移动构造和移动赋值вы хочу Чтобы компилятор генерировал автоматически, должны быть выполнены определенные условия, а именно:

Точно так же суть в том, чтобы различать глубокую копию и мелкую копию.Если распознавание будет глубокой копией, то компилятор не будет ее автоматически генерировать.Только когда это поверхностная копия, она будет автоматически сгенерирована.На самом деле , основное понимание одинаковое.Глубокая копия и поверхностная копия, если класс является пользовательским типом и является мелкой копией, то его конструктор может быть автоматически сгенерирован компилятором в это время, и у программы не будет никаких проблем, но если класс является классом глубокой копии, то его конструктор не может быть автоматически сгенерирован компилятором, а должен контролироваться им самим, иначе он вызовет сбой программы (дважды уничтожается пробел), одним словом , конструкция перемещения и присваивание перемещения вот такие Суть глубокой копии в том, что компилятор не может ею управлять, что приведет к сбою программы, поэтому нам нужно самим управлять вручную Конкретный компилятор позволяет генерировать конструкцию перемещения по умолчанию и переместите условия назначения следующим образом:

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

2. Если вы не реализовали функцию перегрузки присваивания перемещения самостоятельно и не реализовали ни одну из перегрузок деструктора, конструкции копирования и перегрузки присваивания копирования, то компилятор автоматически сгенерирует присваивание перемещения по умолчанию (аналогично), сгенерированное по умолчанию. конструктор перемещения, для элементов встроенного типа, будет выполнять почленное побайтовое копирование (аналогично), для элементов пользовательского типа необходимо проверить, реализует ли элемент назначение перемещения, если оно реализовано, вызовите перемещение присваивание, если нет, вызовите копирование присваивания (аналогично)

Общее: для классов глубокого копирования построение перемещения и присваивание перемещения необходимо реализовать вручную, для мелкого копирования компилятор сгенерирует их автоматически, но суть в том, чтобы вызвать построение копирования и присваивание копирования.

Что такое вариативные шаблоны

Чтобы изучить этот пункт знаний, прежде всего, нам все равно придется начинать со знакомых знаний, поэтому на данный момент мы начинаем с наиболее часто используемого printfинтерфейса
вставьте сюда описание изображения
см., в инструкциях C++ printfпервый параметр интерфейса — const char* format, а второй параметр — ...три точки.Что означают эти два параметра? Напомним, что ранее мы использовали интерфейс для печати данных на языке C printfследующим образом:
вставьте сюда описание изображения
с помощью инструкций и сценариев использования мы можем сделать вывод, что на данный момент const char* formatон представляет собой строковую константу, которая представляет собой содержимое в приведенных выше кавычках, которое используется чтобы указать формат вывода и тип соответствующей переменной, а три точки в последовательности ( ...) представляют переменные, которые нам нужно вывести, и, поскольку нам может потребоваться выводить несколько переменных одновременно, конкретные компиляторы не знают , поэтому второй параметр Разработанная ...форма представляет переменные параметры, так что printfлюбая переменная может быть получена, и данные, соответствующие любой переменной, могут быть напечатаны.Точно так же шаблон переменных параметров, который мы изучим в это время, также такой же, как показано на На следующем рисунке показано:
вставьте сюда описание изображения
Как показано на рисунке выше, мы видим, что когда мы используем шаблон переменных параметров для определения интерфейса функции, эта функция позволяет нам передавать параметры любого типа и любые данные, и после того, как мы используем рекурсию шаблона, в это время Вы можете распечатать этот пакет параметров, то есть все параметры, которые мы передаем в интерфейс.Принцип заключается в том, чтобы использовать шаблон для вывода типа, рекурсивно анализировать пакет параметров и анализировать содержимое пакета параметров по одному.

注意:Существенной особенностью использования шаблонов переменных параметров является то, что три точки ( ...) не имеют никакого отношения к именованию, эти три точки являются ключевыми, и вы должны понимать, что при использовании соответствующего пакета параметров позиции трех точек должны соответствовать грамматические правила, иначе может возникнуть ошибка

Общее: Использование шаблонов переменных параметров может не только решить проблему, связанную с тем, что количество и тип параметров некоторых функциональных интерфейсов не являются фиксированными, но и позволить интерфейсу функции адаптироваться к нескольким типам и количеству параметров, тем самым избегая повторного написания большое количество похожих кодов

вставить серию

После понимания приведенных выше знаний о шаблонах с переменными параметрами все еще очень полезно знать, что шаблоны с переменными параметрами очень полезны во многих аспектах.Например, многие контейнеры в STL инкапсулированы шаблонами с переменными параметрами.Наиболее классическим из них является серия emplace ., следующим образом:
вставьте сюда описание изображения
вставьте сюда описание изображения

Можно обнаружить, что классические контейнеры, такие как список и вектор, добавили серию emplace, и обратите внимание: функция интерфейса emplace такая же, как у вставки, а функция emplace_back такая же, как у push_back, обе из которых являются хвостовыми данными вставки.Иными словами, все контейнеры в STL поддерживают использование шаблонов переменных параметров для вставки данных, то есть, поскольку серия emplace использует шаблоны переменных параметров, поэтому функции, поддерживаемые push_back и insert поддерживаются, серия emplace может их поддерживать, но в некоторых аспектах существуют определенные различия в эффективности вставки, как показано в следующем сравнении:

Сравнение между emplace_back и push_back
Поскольку эти два интерфейса очень похожи в использовании, а шаблоны синтаксиса C++ одинаковы, разница между двумя интерфейсами в реальном использовании очень мала, поэтому я хочу различать эффективность вставки двух интерфейсов. , нам нужно сделать более полное сравнение, следующее мы разделим на два аспекта для сравнения, классы мелкого копирования и классы глубокого копирования, следующим образом:

1. Класс глубокого копирования

Когда мы говорим о классе глубокого копирования, самое главное в настоящее время - различать конструкцию копирования и конструкцию перемещения, поэтому при вставке данных это не исключение. То же самое, что необходимо различать, - это видеть, соответствует ли интерфейс в lvalue и rvalue В разных случаях вызывается конструкция копирования или конструкция перемещения, как показано на следующем рисунке: На этом этапе
вставьте сюда описание изображения
мы можем обнаружить, что когда класс является классом глубокого копирования, будь то lvalue или rvalue , push_back и emplace_back по сути вызывают Интерфейсы построения одинаковы, единственное отличие состоит в том, что при прямой вставке rvalue, потому что push_back нужно сначала выполнить неявное преобразование типа, то есть построить анонимный строковый объект, а затем вызвать перемещение копии , и, поскольку emplace_back использует шаблон переменных параметров, если в это время ему задан строковый тип, то он может напрямую использовать пакет параметров для создания узла и вставки его в конце, поэтому в классе глубокого копирования существенные Разница между push_back и emplace_back заключается в том, что при столкновении со строковым константным типом push_back необходимо неявно преобразовать в значение r, а затем переместить и скопировать, в то время как emplace_back может быть создан напрямую с использованием пакета параметров шаблона, но обратите внимание: эти два метода эффективны. нет разницы на

В целом: для глубокого копирования нет большой разницы между push_back и emplace_back с точки зрения эффективности вставки.

注意:emplace_back может напрямую создавать объекты внутри контейнера через пакет параметров, избегая дополнительного выделения памяти и копирования, поэтому, хотя между ними нет разницы в эффективности, соответствующий интерфейс следует использовать в соответствии с реальным сценарием приложения и требованиями.

2. Классы поверхностного копирования
Аналогично, для классов поверхностного копирования ключевым моментом является различение того, вызывают ли push_back и emplace_back конструкцию копирования или конструкцию перемещения при вставке значений lvalue и rvalue, как показано на следующем рисунке
вставьте сюда описание изображения
: что нет никакой разницы между ними в случае вышеуказанной вставки. В настоящее время то же самое верно для глубокого копирования. Давайте посмотрим, есть ли какая-либо разница между push_back и emplace_back перед константными данными! Как показано на рисунке ниже:
вставьте сюда описание изображения
На этом этапе видно, что по той же причине, когда непосредственно обращены к вставленным данным, push_back должен сначала построить временный объект, а затем скопировать конструкцию, в то время как emplace_back нужно только построить один раз, поэтому в это время, когда требуется поверхностное копирование объекта. Когда скопировано много данных, в это время существует определенный разрыв в эффективности между push_back и emplace_back, потому что push_back необходимо выполнить еще одну конструкцию копирования, но обратите внимание: gap отличается от deep copy только сейчас, хотя в deep copy push_bakc тоже имеет на одну движущуюся копию больше, чем emplace_back, но заметьте, что суть move copy deep copy заключается в выполнении преобразования ресурсов, которое полностью отличается от copy структура мелкой копии, поэтому можно сказать, что нет никакой разницы в эффективности вставки между глубокой и мелкой копиями.

Общее: для неглубокого копирования, когда объем копируемых данных очень велик, существует определенная разница между push_back и emplace_back с точки зрения эффективности вставки.

лямбда-выражение

После получения вышеуказанных знаний я официально перейду в фокус этого блога, знания о лямбда-выражениях Причина, по которой знания о лямбда-выражениях могут быть использованы в качестве темы этого блога, а не шаблонов с переменными параметрами, на самом деле из-за переменных параметров . Шаблоны не очень полезны для нашего обычного кодирования. Нам нужно только знать его и знать его основные методы использования. Нам не нужно глубоко его осваивать, но лямбда-выражения дают нам много преимуществ во многих аспектах кодирования, поэтому нам нужно чтобы освоить их. А использование лямбда-выражений в кодировании может не только сделать наш код более кратким, но и сделать наш код более гибким, который необходимо анализировать из кода сцены. Короче говоря, лямбда-выражения могут очень хорошо улучшить код. и гибкость кода, как показано на следующем рисунке:

Приведение к проблеме:
вставьте сюда описание изображения
из приведенного выше рисунка видно, что когда мы хотим отсортировать пользовательский класс, нам нужны не только данные итератора в объекте класса, но также нужно определенное правило сравнения, но поскольку этот класс является пользовательским type class, поэтому интерфейс sort не знает, по какому принципу следует сортировать, поэтому нам нужно самим реализовать функтор, чтобы указать правила сравнения этого класса, и разрешить интерфейсу sort использовать функтор. Объект вызывает функтор интерфейса, чтобы добиться сортировки в соответствии с нашими собственными ожиданиями, но мы можем обнаружить, что соответствующая реализация функтора и интерфейс сортировки вызывают объект функтора, отношения между ними не близки, мы не можем использовать интерфейс сортировки Объект функтора, называемый в , вы можете сразу увидеть конкретные правила сравнения, но вы должны найти соответствующий функтор, чтобы узнать, на каких правилах основана соответствующая сортировка Читаемость кода очень плохая, поэтому для решения этой проблемы В настоящее время Появится лямбда-выражение, которое мы собираемся изучить. Его появление может очень хорошо решить проблемы такого рода явлений, а именно:

Официально ввести изучение лямбда-выражений

Базовая грамматика: разделена на четыре части

1. Список захвата (обозначается []y)
2. Список параметров (обозначается ()y)
3. Тип возвращаемого значения (обозначается ->y)
4. Тело функции ( {}обозначается y)

Конкретный пример использования показан на рисунке ниже:
вставьте сюда описание изображения
注意:в настоящее время [](int x, int y)->int {return x + y; };он представляет объект лямбда, поэтому приведенный выше код специально означает назначение объекта лямбда объекту добавления, цель: вы можете напрямую использовать объект добавления для вызова лямбда объект, чтобы реализовать лямбда-выражение. Конкретное лямбда-выражение выглядит следующим образом:
вставьте сюда описание изображения
аналогично, в настоящее время мы можем напрямую использовать [](int x, int y)->int {return x + y; };объект для вызова лямбда-выражения или использовать объект добавления для вызова лямбда-выражения.

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

После изучения вышеприведенных знаний давайте подробно обсудим использование лямбда-выражений. Конечно, основное внимание в этой части знаний уделяется разговору о некоторых характеристиках использования лямбда-выражений. Среди них список захвата может захватывать все переменные в контекст и передать их в тело лямбда-функции Использование, список параметров, указать параметры, которые необходимо передать при вызове лямбда-функции,
тип возвращаемого значения, указать тип, соответствующий возвращаемому значению параметра, тело функции, используемое для написания конкретного кода , где разрешено опускать список 注意:параметров и возвращаемое значение, но нельзя опускать список захвата и тело функции.Ниже представлена ​​подробная сцена захвата списка захвата:

вставьте сюда описание изображения

Резюме: лямбда-выражения не только максимально улучшают читаемость кода, но также обладают сильными характеристиками в построении параметров и шаблонах функций. В обычном кодировании лямбда-выражения могут использоваться в первую очередь в определенных сценариях. Все вышеперечисленное касается содержания этого блога, см. ты!

Supongo que te gusta

Origin blog.csdn.net/weixin_74004489/article/details/131120235
Recomendado
Clasificación