I was faced with a need to move a range of elements backward by a certain (possibly zero) displacement. To illustrate, here is some code:
std::vector<int> arr[4] = {{1}, {2}, {3}, {4}};
std::move(arr + 2, arr + 4, arr + 2 - k); // k can be either 0, 1, or 2,
// depending on how far much I want to move the elements
This works as expected when k
is nonzero, but fails when k
is zero (I expect the move to become a no-op when k=0).
The following code, when compiled in GCC will cause arr[2]
and arr[3]
to lose all their elements:
int main() {
std::vector<int> arr[4] = {{1}, {2}, {3}, {4}};
std::move(arr + 2, arr + 4, arr + 2);
for(int i = 0; i < 4; ++i) std::cout << arr[i].size() << ' '; // prints "1 1 0 0 "
std::cout << std::endl;
}
C++ reference says that std::move
's destination should not be in the range [first, last)
, and my code has been in violation of this.
After some digging, I found that self move assignment (i.e. x = std::move(x)
) is not expected to be a no-op, so that seems to be why I'm not allowed to do a no-op range std::move
.
This issue would also happen if I want to move a range of elements forward by a certain (possibly zero) displacement.
To solve this problem, I could check explicitly that k
is nonzero before moving. But is this the idiomatic C++ way?