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:我修改了代码,更明确地指出 bar
在 std::move
之后没有被使用,所以没有非法访问,等等,风险。
Class vector
有两个 push_back
实现:
void push_back( const T& value );
void push_back( T&& value );
第一个复制给定的元素。
第二个尝试通过调用元素的移动构造函数(如果已定义)来"move"它。
使用 move
强制选择第二个实现,它应该重用值而不是仅仅复制一个。
在这种特殊情况下,会发生以下情况:
- 向量
bar
分配在栈上,但它的元素(42)分配在堆上。
- 当您调用
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::PointXYZ
和 int
不是这样的 class,所以 std::move
和 int
或 std::move
和 pcl::PointXYZ
没有意义.
我在一些代码中遇到过这个(为清楚起见删除了细节):
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:我修改了代码,更明确地指出 bar
在 std::move
之后没有被使用,所以没有非法访问,等等,风险。
Class vector
有两个 push_back
实现:
void push_back( const T& value );
void push_back( T&& value );
第一个复制给定的元素。
第二个尝试通过调用元素的移动构造函数(如果已定义)来"move"它。
使用 move
强制选择第二个实现,它应该重用值而不是仅仅复制一个。
在这种特殊情况下,会发生以下情况:
- 向量
bar
分配在栈上,但它的元素(42)分配在堆上。 - 当您调用
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::PointXYZ
和 int
不是这样的 class,所以 std::move
和 int
或 std::move
和 pcl::PointXYZ
没有意义.