std::vector.push_back(std::move(foo)) 有意义吗?

Does std::vector.push_back(std::move(foo)) make sense?

我在一些代码中遇到过这个(为清楚起见删除了细节):

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,而是 class,例如 pcl::PointXYZ,就像我的实际代码中那样,会怎样?

UPDATE:我修改了代码,更明确地指出 barstd::move 之后没有被使用,所以没有非法访问,等等,风险。

Class vector 有两个 push_back 实现:

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

第一个复制给定的元素。

第二个尝试通过调用元素的移动构造函数(如果已定义)来"move"它。

使用 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 调用期间复制的东西。

The std::move looks unnecessary to me, but is it?

这取决于你的意图。

Is the behaviour any different from just foo.push_back(bar);?

是的,foo.push_back(bar); 会将 bar 复制到 foo(由于 std::vector 处理动态分配,因此可能会降低性能)。这也会使 bar 保持不变,您以后可以使用它。

另一方面,foo.push_back(std::move(bar)); 不进行复制并重用 bar 中已分配的内存。请注意,这会使 bar 在移动后处于有效但未指定的状态(也就是你不能使用它,除非你 reinitialize/reassign 它)。

What if instead of an int the element is a class such as pcl::PointXYZ as it is in my actual code?

移动语义仅对使用动态分配(拥有指针)的class类型有用。 pcl::PointXYZint 不是这样的 class,所以 std::moveintstd::movepcl::PointXYZ 没有意义.