Given my combined hashmap and hashset container `HashMapOrSet` defined at

https://github.com/nordlow/phobos-next/blob/master/src/hashmap_or_hashset.d

with deterministic memory management and disabled copy constructions and a member byElement() defined as

        @property auto byElement()() inout
        {
            dln("entering byElement");
            alias This = ConstThis;
// TODO is the use of `&this` incorrect when `this` is an r-value? auto result = ByElement!This((ElementRef!This(cast(This*)&this)));
            result.initFirstNonEmptyBin();
            dln("leaving byElement");
            return result;
        }

        scope auto opSlice()() inout return
        {
            return byElement();
        }

where

        static private struct ByElement(HashMapOrSetType)
        {
            static if (is(ElementType == class))
            {
/// Get reference to front element (key and value).
                @property scope auto front()() return @trusted
                {
/* cast away const from `HashMapOrSetType` for classes * because class elements are currently hashed and compared * compared using their identity (pointer value) `is`
                     */
return cast(ElementType)table.binElementsAt(binIx)[elementOffset];
                }
            }
            else
            {
/// Get reference to front element (key and value).
                @property scope auto front()()
                {
return table.binElementsAt(binIx)[elementOffset];
                }
            }

            public ElementRef!HashMapOrSetType _elementRef;

            alias _elementRef this;
        }

iteration via opSlice works fine when `X` is fed as `this` to `byElement` as an l-value as in

    import digestx.fnv : FNV;
    alias X = HashMapOrSet!(uint, void, null, FNV!(64, true));
    const x = X.withElements([11].s);
    foreach (e; x.byElement) {}

but when `X` is fed as an r-value `this` to `byElement` as in

    import digestx.fnv : FNV;
    alias X = HashMapOrSet!(uint, void, null, FNV!(64, true));
    foreach (e; X.withElements([11].s).byElement) {}

I get a behaviour that seems to indicate that the instance of `X` is freed after `byValue()` (opSlice) returns but before the `ByValue`-range is consumed, resulting in incorrect (undefind) behaviour.

Is it incorrect to use `&this` as follows

auto result = ByElement!This((ElementRef!This(cast(This*)&this)));

in the `byElement`?

If so, is there a way around this problem except for making my container be RC-allocated?

My current proposal for a solution is to make `byElement` a free unary function

    byElement(auto ref X x)

which statically checks via

    static if (__traits(isRef, x))

whether the `X`-instance is passed as either an

- l-value, where my current solution works (ByLvalueElement), or
- r-value, in which the X-instance instead is moved into range (ByRvalueElement).

byValue can be used via UFCS, but this solution removes the possibility for using the opSlice-overload which I can live with.

Further, does all EMSI-container-style containers (with disabled postblit) have the same issue with ranges over r-value instances of its containers?

Reply via email to