Перемещение с помощью вектора :: push_back

18

Предположим, что у меня есть следующий код:

#include <vector>
struct A {
    int a;
    int x;
};
int main() {
    using namespace std;
    A a1;
    A a2;
    vector<A> va;
    va.push_back(a1);
    va.push_back(move(a2));
}

Мне известно, что элементы std :: vector хранятся смежно, в отличие от std :: list. В приведенном выше коде a2 перемещается, но действительно ли нет копирования a2 в вектор va ? В чем разница между va.push_back(a2); и va.push_back(move(a2)); ?

    
задан ggg 20.07.2012 в 05:57
источник
  • В вашем случае std :: move a2 ничего не делает, поскольку это плоский тип (т. е. он не имеет внешних данных) и все равно будет просто скопировать. –  Xeo 20.07.2012 в 05:59
  • @cdhowie Спасибо. исправленный. –  ggg 20.07.2012 в 06:01
  • Возможно, вам захочется прочитать. Может ли кто-нибудь объяснить мне семантику переноса? для введения в перемещение семантики. –  fredoverflow 20.07.2012 в 09:45

3 ответа

28

В вашем случае нет эффективной разницы, поскольку вы используете конструкторы копирования, предоставленные компилятором. Вы увидите заметную разницу в производительности при использовании объектов, которые могут быть построены с возможностью перемещения, и приложите много усилий для копирования. В этом случае использование push_back(x) создаст копию объекта, а push_back(move(x)) скажет push_back() , что он может «украсть» содержимое x , оставив x в непригодном и неопределенном состоянии.

Учтите, если у вас есть вектор списков ( std::vector<std::list<int> > ), и вы хотите нажать список, содержащий 100 000 элементов. Без move() будет скопирована вся структура списка и все 100 000 элементов. С move() некоторые указатели и другие мелкие биты данных перетасовываются, и это все. Это будет намного быстрее и потребует меньше общего объема памяти.

    
ответ дан cdhowie 20.07.2012 в 06:03
источник
  • Почему? перемещение c-tor будет генерироваться автоматически, а не так? –  ForEveR 20.07.2012 в 06:09
  • @ForEveR Не имеет значения, генерируется ли он автоматически или нет, поскольку в структуре A нет перемещений. У вас есть только два ints, и конструктор move сделает то же самое, что и конструктор копирования: присвойте значения, хранящиеся в ints исходного объекта, новому объекту. Нет возможности для оптимизации в сценарии перемещения с этим типом, потому что он уже оптимален, как он может получить. –  cdhowie 20.07.2012 в 06:11
  • @cdhowie Итак, что-то всегда будет скопировано во время переезда? –  ggg 20.07.2012 в 06:39
  • @ggg: «move» - это не какой-то волшебный мазк, который вы накладываете на свой код, который заставляет вещи не случиться. То, что делает «move», позволяет вам указать передачу прав собственности, когда операция копирования потребует выделения новой памяти и т. Д. Если ваша копия не будет делать ничего подобного, то движение не очень полезно. –  Nicol Bolas 20.07.2012 в 08:09
  • @ Томас Возможно. В зависимости от того, существуют ли определенные оптимизации (например, оптимизация небольших строк), это может быть не быстрее - но это не будет медленнее. Обратите внимание, однако, что после vec.push_back (move (str)) объект str остается в неуказанном состоянии. –  cdhowie 03.11.2016 в 19:30
14

При использовании va.push_back(a2) версии будет вызываться vector<T>::push_back(const T&) , когда вы будете использовать va.push_back(move(a2)) version vector<T>::push_back(T&&) будет вызываться ...

Но в вашем случае нет разницы в производительности, поскольку

  

15 Неявно заданный конструктор копирования / перемещения для неединичного класса   X выполняет частичную копию / перемещение своих оснований и членов.

Пункт 12.8 проект n3337.

    
ответ дан ForEveR 20.07.2012 в 05:59
источник
0

Я хочу отметить то, что другие ответы не прошли; заключается в том, что ?.push_back(move(?)) будет медленнее, чем ?.push_back(?) в вашем случае (когда у вас есть объекты с возможностью трехмерного копирования), потому что для перемещения конструктора необходимо установить нуль \ set перемещенный объект, который эффективно вы пишете \ копируете два объекта.

    
ответ дан LyingOnTheSky 19.11.2016 в 18:10
источник
  • Конструктор перемещения не обязан ничего делать с перемещенным объектом. Ему не нужно ничего нуля, если не будут перемещены указатели, которые необходимо сбросить до нуля. (Конструкторы перемещения сгенерированного компилятора не собираются обнулять - нулевой исходный объект.) –  cdhowie 12.09.2017 в 15:54