push back c что это

Разница между push_back и emplace_back

push back c что это. Смотреть фото push back c что это. Смотреть картинку push back c что это. Картинка про push back c что это. Фото push back c что это

push back c что это. Смотреть фото push back c что это. Смотреть картинку push back c что это. Картинка про push back c что это. Фото push back c что это

3 ответа 3

Как видите, push_back ‘у нужен объект типа элемента (или приводимый). А вот emplace ‘у просто передаются аргументы, как конструктору.

P.S. Понятно, что этим конструктором может быть и копирующий конструктор 🙂 Так что

push back c что это. Смотреть фото push back c что это. Смотреть картинку push back c что это. Картинка про push back c что это. Фото push back c что это

push_back добавляет копию объекта (или обеспечивает перемещение, если возможно), а emplace_back создает объект непосредственно в конце вектора, т.е. без лишнего копирования (или перемещения).

push back c что это. Смотреть фото push back c что это. Смотреть картинку push back c что это. Картинка про push back c что это. Фото push back c что это

Я бы сказал, что push_back более универсален. С emplace_back есть нюансы в более сложных алгоритмах. Например при копировании элементов многомерного вектора в одномерный. С виду работает, а компилируешь, ругается. Я бы сказал они один другой дополняют. Если emplace_back работает оставляем его, а если дивные ошибки лезут, то ставим push_back и добавляем <> как я выше показал.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками c++ c++11 vector stl или задайте свой вопрос.

Связанные

Похожие

Подписаться на ленту

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.12.22.41046

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Источник

vector :: push_back () и vector :: pop_back () в C ++ STL

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

вектор :: push_back ()

Функция push_back () используется для вставки элементов в вектор сзади. Новое значение вставляется в вектор в конце после текущего последнего элемента и размер контейнера увеличивается на 1.
Синтаксис:

Ошибки и исключения

1. Сильная гарантия исключения — если выдается исключение, в контейнере не происходит никаких изменений.
2. Если значение, переданное в качестве аргумента, не поддерживается вектором, оно показывает неопределенное поведение.

// Программа CPP для иллюстрации
// функция push_back ()
#include
#include

using namespace std;

vector int > myvector< 1, 2, 3, 4, 5 >;

// Вектор становится 1, 2, 3, 4, 5, 6

вектор :: pop_back () ()

Функция pop_back () используется для выталкивания или удаления элементов из вектора сзади. Значение удаляется из вектора с конца, а размер контейнера уменьшается на 1.
Синтаксис:

Ошибки и исключения

1. No-Throw-Guarantee — если выдается исключение, в контейнере не происходит никаких изменений.
2. Если вектор пуст, он показывает неопределенное поведение.

// Программа CPP для иллюстрации
// функция pop_back ()
#include
#include

using namespace std;

vector int > myvector< 1, 2, 3, 4, 5 >;

// Вектор становится 1, 2, 3, 4

Удаляет ли pop_back () значения вместе с элементами?

Приложение push_back () и pop_back ()
Получив пустой вектор, добавьте к нему целые числа, используя функцию push_back, а затем вычислите его размер.

Алгоритм
1. Добавьте элементы в вектор, используя функцию push_back
2. Проверьте, равен ли размер вектора 0, если нет, увеличьте переменную счетчика, инициализированную как 0, и извлеките задний элемент.
3. Повторяйте этот шаг, пока размер вектора не станет 0.
4. Напечатайте окончательное значение переменной.

// Программа CPP для иллюстрации
// Применение функций push_back и pop_back
#include
#include

Источник

Как именно я использую функции 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 это просто функция, которая добавляет новый элемент в конец этого псевдомассива. Есть, конечно, много тонких деталей, но они несущественны в большинстве случаев.

Основное использование таково:

Лучший способ понять, как это работает, это попробовать использовать его самостоятельно.

Источник

Идеальная передача и универсальные ссылки в C++

Недавно на isocpp.org была опубликована ссылка на статью Eli Bendersky «Perfect forwarding and universal references in C++». В этой небольшой статье есть простой ответ на простой вопрос — для решения каких задач и как нужно использовать rvalue-ссылки.

Одно из нововведений C++11, которое нацелено на увеличение эффективности программ – это семейство методов emplace у контейнеров STL. Например, в std::vector появился метод emplace_back (практически аналог метода push_back) и метод emplace (практически аналог метода insert).
Вот небольшой пример, показывающий предназначение этих новых методов:

Если проследить за вызовами конструкторов и деструкторов класса MyKlass, во время вызова push_back можно увидеть следующее:

Проблема идеальной передачи

Допустим, есть некоторая функция func, принимающая параметры типов E1, E2, …, En. Требуется создать функцию wrapper, принимающую такой же набор параметров. Другими словами – определить функцию, которая передаст принимаемые параметры в другую функцию, не создавая временные переменные, то есть выполнит идеальную передачу.
Для того чтобы конкретизировать задачу, рассмотрим метод emplace_back, который был описан выше. vector::emplace_back передает свои параметры конструктору T не зная ничего о том, чем является T.
Следующим шагом рассмотрим несколько примеров, показывающих как можно добиться подобного поведения без использования нововведений С++11. Для упрощения не будем учитывать необходимость использования шаблонов с переменным количеством параметров аргументов, предположим, что требуется передать только два аргумента.
Первый вариант, который приходит на ум:

Но это очевидно не будет работать как нужно, если func принимает параметры по ссылке, так как wrapper принимает параметры по значению. В этом случае, если func изменяет получаемые по ссылке параметры, это не отразится на параметрах, переданных во wrapper (будут изменены копии, созданные внутри wrapper).
Хорошо, тогда мы можем переделать wrapper, чтобы он принимал параметры по ссылке. Это не будет помехой, если func будет принимать не по ссылке, а по значению, так как func внутри wrapper сделает себе необходимые копии.

Здесь другая проблема. Rvalue не может быть передано в функцию в качестве ссылки. Таким образом вполне тривиальный вызов не скомпилируется:

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

Экспоненциальный рост. Можно представить, сколько веселья это доставит, когда потребуется обработать какое-то разумное количество параметров реальных функций. Чтобы ухудшить ситуацию С++11 добавляет rvalue ссылки, которые тоже нужно учесть в функции wrapper, и это точно не является расширяемым решением.

Сжатие ссылок и особый вывод типа для rvalue-ссылок

Для объяснения того, как в С++11 реализуется идеальная передача, нужно сначала понять два новых правила, которые были добавлены в этот язык программирования.
Начнем с простого – сжатия ссылок (reference collapsing). Как известно, взятие ссылки на ссылку в С++ не допускается, но это иногда может происходить при реализации шаблонов:

Что случится, если вызвать эту функцию следующим образом:

Не позволяйте двойному амперсанду обмануть Вас – t здесь не является rvalue-ссылкой [2]. При появлении в данной ситуации (когда необходим особый вывод типа), T&& принимает особое значение – когда func инстанцируется, T изменяется в зависимости от переданного типа. Если была передана lvalue типа U, то Т становится U&. Если же U это rvalue, то Т становится просто U. Пример:

Это правило может показаться необычным и даже странным. Оно такое и есть. Но, тем не менее, это правило становится вполне очевидным, когда приходит понимание что это правило помогает решить проблему идеальной передачи.

Реализация идеальной передачи с использованием std::forward

Теперь давайте вернемся к нашей описанной выше шаблонной функции wrapper. Вот как она должна быть реализована с использованием С++11:

А вот как реализован forward [3]:

Рассмотрим следующий вызов:

Рассмотрим первый аргумент (второй аналогичен): ii является lvalue, таким образом T1 становится int& в соответствии с правилом особого вывода типа. Получается вызов func(forward (e1), …). Таким образом, шаблон forward инстанцирован типом int& и получаем следующую версию этой функции:

Время применить правило сжатия ссылок:

Другими словами, аргумент передан по ссылке в func, как и требуется для lvalue.
Следующий пример:

Аргумент, полученный по ссылке, приводится к rvalue-ссылке, которую и требуется получить от forward.
Шаблонную функцию forward можно рассматривать как некоторую обертку над static_cast (t), когда T может принять значение U& или U&&, в зависимости от типа входного аргумента (lvalue или rvalue). Теперь wrapper является одним шаблоном, который обрабатывает любые сочетания типов аргументов.
Шаблонная функция forward реализована в С++11, в заголовочном файле «utility», в пространстве имен std.

Еще один момент, который нужно отметить: использование std::remove_reference. На самом деле forward может быть реализован и без использования этой функции. Сжатие ссылок выполнит всю работу, таким образом, применение std::remove_reference для этого избыточно. Однако, эта функция позволяет вывести T& t в ситуации, когда этот тип не может быть выведен (согласно стандарту С++, 14.8.2.5), поэтому необходимо явно указывать параметры шаблона при вызове std::forward.

Универсальные ссылки

В своих выступлениях, постах в блоге и книгах, Скотт Майерс дает наименование «универсальные ссылки» (universal reference) для rvalue-ссылок, которые в контексте вывода типов. Удачное это наименование или нет, сложно сказать. Что касается меня, когда я первый раз прочитал относящуюся к данной теме главу из новой книги «Effective C++», я почувствовал, что запутался. Более-менее стало все понятно позже, когда я разобрался с лежащими в основе этого механизмами (сжатия ссылок и правил особого вывода типов).
Ловушка заключается в том, что фраза «универсальные ссылки» [4] конечно более кратка и красива, чем «rvalue-ссылки в контексте вывода типов». Но если есть желание на самом деле понять некоторый код, не получится избежать полного описания.

Примеры использования идеальной передачи

Идеальная передача довольно полезна, потому что делает возможным программирование на более высоком уровне. Функции высшего порядка – это функции, которые могут принять другие функции в качестве аргументов или возвращать их. Без идеальной передачи, применение функций высшего порядка довольно обременительно, так как нет удобного способа передать аргументы в функцию внутри функции-обертки. Под термином «функция» я здесь кроме самих функций также имею в виду и классы, конструкторы которых фактически тоже являются функциями.
В начале данной статьи я описывал метод контейнеров emplace_back. Другой хороший пример – это стандартная шаблонная функция make_unique, которую я описывал в предыдущей статье:

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

Ссылки на источники

От переводчика: на CppCon2014 многими (в том числе Мейерсом, Страуструпом, Саффером) было принято решение использовать термин forwarding references вместо universal references.

Источник

Почему push_back медленнее, чем operator [] для предыдущего выделенного вектора

Я только что прочитал этот блог http://lemire.me/blog/archives/2012/06/20/do-not-waste-time-with-stl-vectors/ сравнивая производительность operator[] назначение и push_back в памяти предварительно зарезервированы std::vector и я решил попробовать это сам. Операция проста:

Тестовый код прилагается ниже:

Решение

push_back делает проверку границ. operator[] не. Так что даже если вы зарезервировали место, push_back будет иметь дополнительную условную проверку, что operator[] не будет иметь. Кроме того, это увеличит size значение (резерв устанавливает только capacity ), поэтому он будет обновлять это каждый раз.

Короче, push_back делает больше, чем что operator[] делает — вот почему это медленнее (и точнее).

Другие решения

Первое интересное наблюдение заключается в том, что в оригинальном тесте, используя new и работает на необработанном массиве помедленнее чем с помощью vector bigarray(N); а также operator[] — больше, чем фактор 2. Еще более интересно то, что вы можете получить одинаковую производительность для обоих, вставив дополнительный memset для необработанного варианта массива:

Вывод, конечно, заключается в том, что PROFILE измеряет что-то другое, чем ожидалось. Якк и я предполагаем, что это как-то связано с управлением памятью; из комментария Якка к ОП:

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

Я подумал о чем-то подобном, поэтому попробовал небольшой тест для этой гипотезы, коснувшись определенных страниц «набранным набором записей» (инструмент профилирования мог бы получить более надежные результаты):

Изменяя шаг от каждая половина страницы в каждая 4-я страница оставив его полностью, мы получаем хороший переход времени от vector bigarray(N); дело в new int[N] случай, когда нет memset был использован.

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

Точно так же, если мы добавим немного UB (но проверим результаты позже):

Но требуется ли разветвление в push_back или дополнительная операция?

Я проверил это с помощью vector bigarray(N); + operator[] вариант, и вставка вызова функции, которая имитирует поведение push_back :

Интересным моментом является то, что происходит, когда я добавляю приращение к silly_branch :

Теперь модифицированный routine2_modified работает в 2 раза медленнее, чем оригинал routine2 наравне с предлагаемым routine3_modified выше, что включает в себя UB для фиксации страниц памяти. Я не нахожу это особенно удивительным, так как он добавляет еще одну запись к каждой записи в цикле, поэтому у нас в два раза больше работы и в два раза больше времени.

Что ж, вам пришлось внимательно посмотреть на инструменты сборки и профилирования, чтобы проверить гипотезы управления памятью, а дополнительная запись — хорошая гипотеза («правильная»). Но я думаю, что намеки достаточно сильны, чтобы утверждать, что происходит нечто более сложное, чем просто ветка, которая делает push_back помедленнее.

Вот полный тестовый код:

Пробный прогон на старом & медленный компьютер; нота:

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

Я могу ответить на ваш второй вопрос. Хотя вектор предварительно выделен, push_back все равно должен проверять доступное пространство каждый раз, когда вы вызываете push_back. С другой стороны, оператор [] не выполняет никаких проверок и просто предполагает наличие свободного места.

Это расширенный комментарий, а не ответ, призванный помочь улучшить вопрос.

Рутина 4 вызывает неопределенное поведение. Ты пишешь за конец size массива. Замените резерв с изменением размера, чтобы устранить это.

Подпрограммы с 3 по 5 ничего не могли сделать после оптимизации, так как они не имеют видимого результата.

insert( vec.end(), src.begin(), src.end() ) где src диапазон генератора произвольного доступа ( boost вероятно есть) может подражать new версия, если ваш insert умный

Дублирование routine1 кажется смешным — случайно ли это меняет время?

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *