问题
#include <vector>
struct A { int a[100]; };
void foo (const A& a) {
std::vector<A> vA;
vA.push_back(std::move(a)); // how does move really happen?
}
int main () {
A a;
foo(a);
}
The above code compiles fine. Now everywhere it's written that move
avoids copying.
Following are my queries:
- Does the
move
really work when one deals with a lvalue [non]-const
reference? - Even with "rvalue reference", how is the copy avoided when the object is inserted into a standard container like above?
e.g.
void foo (A&& a) { // suppose we invoke this version
std::vector<A> vA;
vA.push_back(std::move(a)); // how copy is avoided?
}
回答1:
std::move
doesn't do a move. It actually casts the lvalue reference to an rvalue reference. In this case, the result of the move is a const A &&
(which is totally useless by the way).
std::vector
has an overload for a const A &
and a A &&
, so the overload with const A &
will get chosen and the const A &&
is implicitly casted to const A &
The fact that std::move
can be called on const objects, is strange/unexpected behavior for most programmers, though it somehow is allowed. (Most likely they had a use case of it, or none to prevent it)
More specific for your example, the move constructor of the class A will get called. As A is a POD, this most likely will just do a copy as all bits just have to move/copied to the new instance of A.
As the standard only specifies that the original object has to be in a valid though unspecified state, your compiler can keep the bits in A in place and doesn't have to reset them all to 0. Actually, most compilers will keep these bits in place, as changing them requires extra instructions, which is bad for performance.
回答2:
Created a snippet to show it. Though in your example default constructor will be called, but you get the idea.
#include <vector>
#include <iostream>
struct A {
int a[100];
A() {}
A(const A& other) {
std::cout << "copy" << std::endl;
}
A(A&& other) {
std::cout << "move" << std::endl;
}
};
void foo(const A& a) {
std::vector<A> vA;
vA.push_back(std::move(a));
}
void bar(A&& a) {
std::vector<A> vA;
vA.push_back(std::move(a));
}
int main () {
A a;
foo(a); // "copy"
bar(std::move(a)); // "move"
}
来源:https://stackoverflow.com/questions/38917130/does-stdmove-work-with-lvalue-references-how-does-stdmove-work-on-standard