1

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?

Bernard
  • 5,209
  • 1
  • 34
  • 64

1 Answers1

3

Yes, such a check would be very typical. Even if x[i]=x[i+0]; were a no-op you would still want to skip the loop processing if possible and that's what the zero-displacement check would provide.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23