called copy constructor in foreach with ref on Range

Jonathan M Davis newsgroup.d at jmdavisprog.com
Mon Jun 22 19:03:44 UTC 2020


On Monday, June 22, 2020 10:59:45 AM MDT kinke via Digitalmars-d-learn wrote:
> If copying a range is considered to be generally unsafe and a
> common pitfall (vs. the save() abomination), maybe range-foreach
> shouldn't allow any lvalue ranges in the 1st place, thus not
> making any copies and forcing the user to specify some rvalue (as
> returned by `range.save()`, or `move(range)` if destructive
> iteration is indeed intended).

Copying ranges isn't a problem. Almost all range-based code copies ranges
quite a bit (e.g. almost all range-based functions take a range by value,
and chaining range-based function calls wouldn't work if it didn't). Rather,
it's using the original after a copy has been made that's a problem (at
least in generic code), because the semantics of copying aren't part of the
range API and can vary wildly depending on the type.

Really, the issues with copying were not properly taken into account when
the range API was created, and mistakes were made. If we were to rework the
range API at this point, we would probably get rid of save and require that
copying be equivalent to save for forward ranges (which would then make it
illegal for classes to be forward ranges without wrapping them in a struct).
That would fix the problem for forward ranges, but basic input ranges can't
have those semantics, or they could be forward ranges, so exactly what the
correct solution would be is debatable, and if generic code operates on both
basic input ranges and forward ranges, the copying semantics won't always be
the same, which is the problem we have now. So, if we were to rework the
range API, it's one of the open problems that needs to be sorted out.

Regardless, as things stand, because copying a range can have reference
semantics, value semantics, or something in between, in practice, that means
that generic code cannot use a range once it's been copied, because the
semantics will vary from type to type. The copy can be used (and most
range-based code relies on that), but the original needs to be left alone.
Non-generic code has more leeway, because it can rely on the behavior of
specific range types, but with generic code, you have to be careful. And
foreach is just one of the places where the issue of not using the original
after making a copy comes up.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list