pop back c что делает
Как именно я использую функции push_back и pop_back ()? Я посмотрел их в следующем, но до сих пор не понимаю,
Решение
Если вы новичок, просто прочитайте дополнительные квалификаторы, такие как const, & а также &&, Методы в STL реализованы таким образом, что они ведут себя согласованно при всех перегрузках:
Я приведу небольшой пример здесь:
Теперь подробнее об ответе:
Причина, по которой он реализован таким образом, заключается в том, что он может предотвратить ненужную копию. (Сначала скопируйте аргумент в стек для вызова push_back и во второй раз скопируйте его в позицию в векторе. Первая копия не нужна и сохраняется const ссылка.)
Это все красиво и просто, но есть случаи, когда компилятору не разрешается брать ссылку на значение и передавать ее в функцию. В случае временных значений, нет никакой ссылки, чтобы взять, потому что нет никакой переменной в памяти. Возьмите следующую строку для примера.
Теперь мы можем снова посмотреть на пример:
Другие решения
Это должно показать вам, как вы можете использовать оба из них.
отталкивать():
pop_back ():
Если вам нужно больше разъяснений:
push_back(const T& val) добавляет свой параметр в конец вектора, эффективно увеличивая размер на 1, если емкость вектора будет превышена его размером.
pop_back() не принимает никаких параметров и удаляет последний элемент вектора, эффективно уменьшая размер на 1.
Обновить:
Я пытаюсь ответить на ваши вопросы один за другим, если что-то неясно, дайте мне знать.
Я не понимаю, как заполнить аргументы (const value_type& вал) & (тип ценности&& вал)
Вы, как программист, делаете НЕ выберите способ передачи аргументов в push_back (), компилятор сделает это за вас автоматически, в большинстве случаев.
Я не понимаю второе предложение в разделе параметров. (Это слишком многословно для меня, чтобы получить). Я понимаю, что такое Val
В чем разница и / или преимущества void push_back (const value_type& Val); & void push_back (value_type&& вал) и что вы предлагаете мне использовать?
void push_back(value_type&&) принимает аргумент, который затем перемещается в контейнер (этот тип выражений называется Rvalue выражения).
Использование любого из двух зависит от результатов, которые вы хотите достичь.
Я не понимаю, как заполнить аргументы (const value_type& вал) & (тип ценности&& вал)
В большинстве случаев вам не нужно думать о том, какую версию использовать, так как об этом позаботится компилятор. Вторая версия будет вызываться для любого аргумента rvalue, а первая — для остальных. В редком случае, когда вы хотите, чтобы была вызвана вторая перегрузка, вы можете использовать std::move явно преобразовать выражение аргумента в xvalue (что-то вроде rvalue).
Я не понимаю второе предложение в разделе параметров. (Это слишком многословно для меня, чтобы получить). Я понимаю, что такое Val
Тип элемента value_type — это тип элементов в контейнере, определенный в векторе как псевдоним его первого параметра шаблона (T).
Поскольку вектор — это не обычный тип, а шаблон, вы должны указать параметры типа (которые заключаются в угловые скобки <> после vector ) при определении переменной. Внутри vector спецификация шаблона это тип параметра T затем связывается с value_type :
Это не дает пример, который я могу понять очень хорошо. Могу ли я получить другие примеры с использованием векторов или ссылок на видео, которые лучше объясняют использование функции на практике?
Главное, что вам нужно помнить, это то, что vector ведет себя как простой массив, но с динамически изменяемым размером и некоторой дополнительной информацией, такой как его длина. push_back это просто функция, которая добавляет новый элемент в конец этого псевдомассива. Есть, конечно, много тонких деталей, но они несущественны в большинстве случаев.
Основное использование таково:
Лучший способ понять, как это работает, это попробовать использовать его самостоятельно.
Урок №106. Ёмкость вектора
Обновл. 13 Сен 2021 |
Мы уже знаем, что такое std::vector в языке С++ и как его можно использовать в качестве динамического массива, который запоминает свою длину и длина которого может быть динамически изменена по мере необходимости. Хотя использование std::vector в качестве динамического массива — это самая полезная и наиболее часто применяемая его особенность, но он также имеет и некоторые другие способности, которые также могут быть полезными.
Длина vs. Ёмкость
Рассмотрим следующий пример:
Мы можем сказать, что длина массива равна 12, но используется только 7 элементов (которые мы, собственно, выделили).
А что, если мы хотим выполнять итерации только с элементами, которые мы инициализировали, оставляя в резерве неиспользованные элементы для будущего применения? В таком случае нам потребуется отдельно отслеживать, сколько элементов было «использовано» из общего количества выделенных элементов. В отличие от фиксированного массива или std::array, которые запоминают только свою длину, std::vector имеет два отдельных свойства:
Длина в std::vector — это количество фактически используемых элементов.
Ёмкость (или «вместимость») в std::vector — это количество выделенных элементов.
Рассмотрим пример из урока о std::vector:
Результат выполнения программы:
The length is: 6
0 1 2 3 0 0
В примере, приведенном выше, мы использовали функцию resize() для изменения длины вектора до 6 элементов. Это сообщает массиву, что мы намереваемся использовать только первые 6 элементов, поэтому он должен их учитывать, как активные (те, которые фактически используются). Следует вопрос: «Какова ёмкость этого массива?».
Мы можем спросить std::vector о его ёмкости, используя функцию capacity():
Результат на моем компьютере:
The length is: 6
The capacity is: 6
В этом случае функция resize() заставила std::vector изменить как свою длину, так и ёмкость. Обратите внимание, ёмкость всегда должна быть не меньше длины массива (но может быть и больше), иначе доступ к элементам в конце массива будет за пределами выделенной памяти!
Зачем вообще нужны длина и ёмкость? std::vector может перераспределить свою память, если это необходимо, но он бы предпочел этого не делать, так как изменение размера массива является несколько затратной операцией. Например:
Результат выполнения программы:
length: 6 capacity: 6
length: 4 capacity: 6
Обратите внимание, хотя мы присвоили меньшее количество элементов массиву во второй раз — он не перераспределил свою память, ёмкость по-прежнему составляет 6 элементов. Он просто изменил свою длину. Таким образом, он понимает, что в настоящий момент активны только первые 4 элемента.
Оператор индекса и функция at()
Диапазон для оператора индекса [] и функции at() основан на длине вектора, а не на его ёмкости. Рассмотрим массив из вышеприведенного примера, длина которого равна 4, а ёмкость равна 6. Что произойдет, если мы попытаемся получить доступ к элементу массива под индексом 5? Ничего, поскольку индекс 5 находится за пределами длины массива.
Обратите внимание, вектор не будет изменять свой размер из-за вызова оператора индекса или функции at()!
std::vector в качестве стека
Если оператор индекса и функция at() основаны на длине массива, а его ёмкость всегда не меньше, чем его длина, то зачем беспокоиться о ёмкости вообще? Хотя std::vector может использоваться как динамический массив, его также можно использовать в качестве стека. Мы можем использовать 3 ключевые функции вектора, которые соответствуют 3-м ключевым операциям стека:
функция push_back() — добавляет элемент в стек.
функция back() — возвращает значение верхнего элемента стека.
функция pop_back() — вытягивает элемент из стека.
Векторы в C++: для начинающих
Всем привет! До этого дня мы использовали чистые массивы. Чистые — это значит простые массивы, не имеющие у себя в багаже различных функций. В этом уроке мы пройдем нечистые массивы — векторы.
Быстрый переход по статье:
Что такое вектор (vector)
Вектор — это структура данных, которая уже является моделью динамического массива.
Давайте вспомним о том, что для создания динамического массива (вручную) нам нужно пользоваться конструктором new и вдобавок указателями. Но в случае с векторами всего этого делать не нужно.
Вообще, по стандарту пользоваться динамическим массивом через конструктор new — не есть правильно. Так как в компьютере могут происходить различные утечки памяти.
Как создать вектор (vector) в C++
Кстати, сейчас и в будущем мы будем использовать именно шаблон вектора. Например, очередь или стек, не созданные с помощью массива или вектора, тоже являются шаблонными.
Далее, чтобы объявить вектор, нужно пользоваться конструкцией ниже:
В примере выше мы создали вектор строк.
Кстати, заполнить вектор можно еще при инициализации (другие способы мы пройдем позже — в методах вектора). Делается это также просто, как и в массивах. Вот так:
После имени вектора ставим знак равенства и скобки, в которых через пробел указываем значение элементов.
Такой способ инициализации можно использовать только в C++!
Второй способ обратиться к ячейке
Но в C++ есть еще один способ это сделать благодаря функции — at(). В скобках мы должны указать индекс той ячейки, к которой нужно обратиться.
Вот как она работает на практике:
Давайте запустим эту программу:
Как указать количество ячеек для вектора
Указывать размер вектора можно по-разному. Можно это сделать еще при его инициализации, а можно хоть в самом конце программы. Вот, например, способ указать длину вектора на старте:
Так в круглых скобках () после имени вектора указываем первоначальную длину. А вот второй способ:
Вы можете задать логичный вопрос:»А в чем разница?». Давайте создадим два вектора и по-разному укажем их количество ячеек.
Как видим, в первом случае мы вывели три нуля, а во втором: 17, 0, 0.
Все потому, что при использовании первого способа все ячейки автоматически заполнились нулями.
При объявлении чего-либо (массива, вектора, переменной и т.д) мы выделяем определенное количество ячеек памяти, в которых уже хранится ненужный для ПК мусор. В нашем случае этим мусором являются числа.
Поэтому, когда мы вывели второй вектор, в нем уже находились какие-то рандомные числа — 17, 0, 0. Обычно они намного больше. Можете кстати попробовать создать переменную и вывести ее значение.
Нужно помнить! При использовании второго способа есть некоторый плюс — по времени. Так как для первого способа компилятор тратит время, чтобы заполнить все ячейки нулями.
Как сравнить два вектора
Если в середине программы нам понадобиться сравнить два массива, мы, конечно, используем цикл for и поочередно проверим все элементы.
Вектор снова на шаг впереди! Чтобы нам сравнить два вектора, потребуется применить всего лишь оператор ветвления if.
pop_back () возвращаемое значение?
Почему не pop_back() есть возвращаемое значение? Я гуглил по этому поводу и обнаружил, что это делает его более эффективным. Это единственная причина сделать это в стандарте?
Решение
Я думаю, что что-то связано с тем, что копирование экземпляра последнего объекта может вызвать исключение. При этом вы теряете свой объект, так как pop_back () действительно удалил его из вашего контейнера. Лучше всего с несколькими строками кода:
Другие решения
Эффективность имеет мало (или вообще ничего) общего с этим.
Причина не столько в эффективности, сколько в исключительной безопасности. Контейнерный класс может использоваться для хранения любых объектов. Было бы невозможно реализовать pop_back () безопасным способом исключения, если бы функция возвращала объект после удаления его из контейнера, потому что возвращение значения объекта включает конструкцию копирования.
Это фактическая реализация vector :: pop_back () в стандартной библиотеке GNU C ++:
Вот как это будет выглядеть, если он вернет последний элемент в конце:
Это включает в себя две конструкции копирования, на save = back() заявление и при возврате копии объекта. Нет никаких гарантий, что выражение возврата не сгенерирует исключение после того, как элемент был уничтожен из контейнера.
Ну, сколько должно быть причин?
Это позволяет избежать потенциально дорогостоящего копирования объекта, когда вы просто хотите удалить его из контейнера. С ++ имеет философию не платить за то, что вам не нужно.
Почему бы это вернуть значение? Вы всегда можете получить доступ к значению в любое время до его снятия — нет необходимости pop_back обеспечить эту функциональность.
Использование функции Vector Pop_Back () в C++
Размер вектора можно уменьшить, используя различные встроенные функции C ++. Функция pop_back () — одна из них. Он используется для удаления последнего элемента вектора сзади и уменьшения размера вектора на 1. Но последний элемент вектора не удаляется навсегда, как функция erase (). В этом руководстве были объяснены различные варианты использования этой функции.
Синтаксис:
Эта функция не имеет аргументов и ничего не возвращает.
Предварительные условия:
Прежде чем проверять примеры этого руководства, вы должны проверить, установлен ли компилятор g ++ в системе. Если вы используете Visual Studio Code, установите необходимые расширения для компиляции исходного кода C ++ и создания исполняемого кода. Здесь приложение Visual Studio Code было использовано для компиляции и выполнения кода C ++. Способы уменьшения размера вектора с помощью функции pop_back () показаны в следующей части этого руководства.
Пример 1: удалить несколько элементов из вектора
Создайте файл C ++ со следующим кодом, чтобы удалить два элемента из контейнера вектора путем уменьшения размера вектора с помощью функции pop_back (). В коде объявлен вектор из 5 строковых значений. Функция pop_back () вызывалась здесь два раза, чтобы временно удалить два последних элемента из вектора и уменьшить размер вектора на 2. Содержимое вектора было напечатано два раза до и после использования функции pop_back ().
using namespace std ;
//Declare a vector of string values
cout «The values of the vector : \n « ;
//Iterate the vector using loop to print the values
for ( int i = ; i flowers. size ( ) ; ++ i )
//Remove the last two values from the vector
cout « \n The values of the vector after remove : \n « ;
//Iterate the vector using loop to print the values
for ( int i = ; i flowers. size ( ) ; ++ i )
Следующий вывод появится после выполнения вышеуказанного кода.
Пример 2: Создать новый вектор из другого вектора
Создайте файл C ++ со следующим кодом для вставки определенных значений в пустой вектор из другого вектора путем удаления элементов с помощью функции pop_back (). В коде объявлены вектор из 8 целых чисел и пустой вектор целочисленного типа. Цикл while использовался для перебора каждого элемента первого вектора и вставки элемента в новый вектор, если число делится на 2. Здесь также была вычислена сумма всех четных чисел. Каждый элемент первого вектора будет удален функцией pop_back () на каждой итерации цикла, чтобы достичь условия завершения цикла.
using namespace std ;
//Declare a vector of integer data
//Declare an empty vector
vector int > newVector ;
cout «The values of the original vector : \n « ;
//Iterate the vector using loop to print the values
for ( int i = ; i intVector. size ( ) ; ++ i )
//Initialize the result
//Iterate the loop until the vector becomes empty
Find out the even numbers to insert into the newVector
and calculate the sum of the even numbers
if ( intVector. back ( ) % 2 == )
result + = intVector. back ( ) ;
newVector. push_back ( intVector. back ( ) ) ;
//Remove element from the end of the intVactor
cout «The values of the new vector : \n « ;
//Iterate the vector using loop to print the values
for ( int i = ; i newVector. size ( ) ; ++ i )
cout «The sum of all even numbers : « result ‘ \n ‘ ;
Следующий вывод появится после выполнения вышеуказанного кода. В первом векторе было три четных числа. Есть 8, 2 и 4.
Пример 3: проверьте, удален ли последний элемент вектора
Ранее упоминалось, что pop_back () не удаляет элементы из вектора навсегда, а удаляет элемент только за счет уменьшения размера вектора. Таким образом, удаленный элемент остается в той же позиции, пока размер вектора не увеличится и не заменит элемент другим элементом. Создайте файл C ++ со следующим кодом, чтобы проверить, существует ли элемент, удаленный функцией pop_back (), или нет. Последняя позиция исходного вектора была напечатана до и после использования функции pop_back ().
using namespace std ;
//Declare a vector of integer data
//Declare an empty vector
vector int > newVector ;
//Declare an integer variable
//Print the last element based on the size of the vector
length = intVector. size ( ) ;
cout «The current size of the vector:» length « \n « ;
cout «The last value of the vector before remove:» intVector [ length — 1 ] « \n « ;
//Remove the element from the end of the vector
//Print the last element based the size of the vector after remove
length = intVector. size ( ) ;
cout «The current size of the vector:» length « \n « ;
cout «The last value of the vector after remove:» intVector [ length ] « \n « ;
Следующий вывод появится после выполнения вышеуказанного кода. Выходные данные показывают, что размер вектора уменьшился на 1, но элемент последней позиции исходного вектора все еще существует.
Заключение
В этом руководстве на простых примерах описаны три различных использования функции pop_back (). Основная цель использования этой функции будет понятна читателям после практики примеров из этого руководства.