called copy constructor in foreach with ref on Range

Jonathan M Davis newsgroup.d at jmdavisprog.com
Mon Jun 22 16:25:11 UTC 2020


On Sunday, June 21, 2020 2:25:37 PM MDT kinke via Digitalmars-d-learn wrote:
> A foreach over a custom range makes an initial copy, so that the
> original range is still usable after the foreach (not empty).

No, it's not so that the range will be useable afterwards. In fact, for
generic code, you must _never_ use a range again after passing it to
foreach, because the copying semantics of ranges are not specified, and you
can get radically different behavior depending on what the copying semantics
of a range are (e.g. if it's a class, then it's just copying the reference).
In general, you should never use a range after it's been copied unless you
know exactly what type of range you're dealing with and what its copying
behavior is. If you want an independent copy, you need to use save.

The reason that foreach copies the range is simply due to how the code is
lowered. e.g.

    foreach(e; range)
    {
    }

essentially becomes

    for(auto r = range; !r.empty; r.popFront())
    {
        auto e = r.front;
    }

And the fact that a copy is made is likely simply a result of it mimicking
what happens with arrays. Either way, you should never be doing something
like

    foreach(e; range)
    {
    }

    auto v = range.front;

in generic code. It needs to be

    foreach(e; range.save)
    {
    }

    auto v = range.front;

instead.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list