问题
I have come across this in some code (details eliminated for clarity):
std::vector<std::vector<int>> foo;
{
std::vector<int> bar = {42};
foo.push_back(std::move(bar)); // Hmmm...
} // Indicate `bar` is no longer needed.
The std::move
looks unnecessary to me, but is it? Is the behaviour any different from just foo.push_back(bar);
? What if instead of an int
the element is a class such as pcl::PointXYZ as it is in my actual code?
UPDATE: I have altered the code to more explicitly indicate that bar
is not used after the std::move
, so there is no illegal access, etc, risk.
回答1:
Class vector
has two push_back
implementations:
void push_back( const T& value );
void push_back( T&& value );
The first one does copy of the element given.
The second tries to "move" it by calling element's move constructor (if it's defined).
Using move
forces to pick the second implementation which is supposed to reuse the value rather than just copying one.
In this particular case this is what gonna happen:
- Vector
bar
is allocated on the stack, but its elements (42) are allocated on the heap. - When you call
foo.push_back(...)
,foo
allocates on the heap a new vector, which is gonna bebar
s copy. Let's call itbaz
:) Depending on whichpush_back
implementation is called the following will happen then:void push_back( const T& value );
: in this case allbar
's elements will be copyed tobaz
as well.void push_back( T&& value );
in this casebaz
will receive a pointer tobar
's elements, so no copy operations are performed. But it is crucial for understanding thatbar
will be deprived of its elemets (nowbaz
owns them), sobar
shoun't be used aftermove
.
It isn't that important what kind of the elements are (plain ints or pcl::PointXYZ
), since only the first vector has allocated the memory for the elements, and the pointer to that memory is the only thing that is copyed during the move
call.
回答2:
The std::move looks unnecessary to me, but is it?
It depends on your intention.
Is the behaviour any different from just foo.push_back(bar);?
Yes, foo.push_back(bar);
will copy bar
into foo
(potentially a performance penalty as std::vector
deals with dynamic allocations). This will also leave bar
the same and you can use it afterwards.
On the other hand, foo.push_back(std::move(bar));
makes no copies and reuses the already allocated memory in bar
. Note that this leaves bar
in a valid but unspecified state after the move (aka you can't use it unless you reinitialize/reassign it).
What if instead of an int the element is a class such as pcl::PointXYZ as it is in my actual code?
Move-semantics are only useful for class-types which make use of dynamic allocations (owning pointers). pcl::PointXYZ
and int
are no such classes, so it makes no sense to std::move
an int
or std::move
a pcl::PointXYZ
.
来源:https://stackoverflow.com/questions/50227213/does-stdvector-push-backstdmovefoo-make-sense