Search code examples
c++for-loopmovemove-semantics

std::move whole range-expression in range-based for loop


In GitHub repositories there are not few examples where the range-expression in range-based for loop is surrounded in std::move, e.g. in pytorch:

...
outputs = (*call_op)(schema, std::move(inputs), std::move(outputs));

for (auto&& output : std::move(outputs)) {
   torch::jit::push(*stack, std::move(output));
}

Since output here just iterates over the elements of std::move(outputs) and we have std::move(output) inside loop body, does for-loop is really different from the variant without the first std::move:

for (auto&& output : outputs) {
   torch::jit::push(*stack, std::move(output));
}

and if yes, can the difference be observed with some classes from the standard library or only with some specially designed ones?


Solution

  • The range-based for statement is defined by translation:

    {
       init-statement_opt
       auto &&range = for-range-initializer ;
       auto begin = begin-expr ;
       auto end = end-expr ;
       for ( ; begin != end; ++begin ) {
          for-range-declaration = * begin ;
          statement
       }
    }
    

    where begin-expr and end-expr either are range.begin() and range.end(), or are begin(range) and end(range), dependent on whether lookup for the former succeeds.

    This means that within begin-expr and end-expr, range is an lvalue, regardless of whether for-range-initializer is an lvalue or an xvalue (or even a prvalue).

    So wrapping a for-range-initializer in std::move() will not have any effect on program behavior.