Имеет ли смысл std :: vector.push_back (std :: move (foo))? - PullRequest
0 голосов
/ 08 мая 2018

Я сталкивался с этим в некотором коде (детали для ясности исключены):

std::vector<std::vector<int>> foo;
{
    std::vector<int> bar = {42};
    foo.push_back(std::move(bar)); // Hmmm...
} // Indicate `bar` is no longer needed.

std::move мне кажется ненужным, но так ли это? Отличается ли поведение от foo.push_back(bar);? Что если вместо int элемент является классом, таким как pcl::PointXYZ, как в моем реальном коде?

ОБНОВЛЕНИЕ : Я изменил код, чтобы более явно указать, что bar не используется после std::move, поэтому нет незаконного доступа и т. Д., Риск.

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

std :: move кажется мне ненужным, но так ли это?

Это зависит от вашего намерения.

Отличается ли поведение от просто foo.push_back (bar);?

Да, foo.push_back(bar); скопирует bar в foo (потенциально снижение производительности, поскольку std::vector имеет дело с динамическим распределением). Это также оставит bar прежним, и вы сможете использовать его позже.

С другой стороны, foo.push_back(std::move(bar)); не копирует и повторно использует уже выделенную память в bar. Обратите внимание, что это оставляет bar в допустимом, но неопределенном состоянии после перемещения (иначе вы не можете использовать его, пока не переинициализируете / переназначите его).

Что если вместо int элемент является классом, таким как pcl :: PointXYZ как это в моем фактическом коде?

Семантика перемещения полезна только для типов классов, которые используют динамическое распределение (владеющие указателями). pcl::PointXYZ и int не являются такими классами, поэтому нет смысла std::move int или std::move a pcl::PointXYZ.

0 голосов
/ 08 мая 2018

Класс vector имеет две push_back реализации:

void push_back( const T& value );
void push_back( T&& value );

Первый делает копию данного элемента.

Второй пытается «переместить» его, вызвав конструктор перемещения элемента (если он определен).

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

В данном конкретном случае это произойдет:

  1. Вектор bar размещается в стеке, но его элементы (42) размещаются в куче.
  2. Когда вы звоните foo.push_back(...), foo выделяет в куче новый вектор, который будет bar с копией. Давайте назовем это baz :) В зависимости от того, какая реализация push_back вызвана, тогда произойдет следующее:
    • void push_back( const T& value );: в этом случае все элементы bar будут скопированы также в baz.
    • void push_back( T&& value ); в этом случае baz получит указатель на элементы bar, поэтому операции копирования не выполняются. Но важно понимать, что bar будет лишен своих элементов (теперь baz владеет ими), поэтому bar не должно использоваться после move.

Не так важно, что это за элементы (простые целые или pcl::PointXYZ), так как только первый вектор выделил память для элементов, и указатель на эту память - единственное, что копируется во время move звонка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...