On Thursday, 18 February 2021 at 08:29:48 UTC, kinke wrote:
Nope, Paul is right, the copy ctors don't solve anything in this regard. Simplest example I could come up with: https://run.dlang.io/is/TgxyU3

I found that example very confusing, as it does not contain an explicit copy constructor, violate memory safety, or output incorrect results.

However, I experimented with it and I think figured out what you're getting at? Copy constructors (and postblits) may not be called for moves. I guess that makes sense...

///////////////////////////
import std.stdio : write, writeln;

struct S {
    private const(S*) self, old = null;

    this(bool refSelf) inout pure @trusted {
        if(refSelf)
                self = &this;
    }
    @disable this(this) inout pure @safe;
    this(scope ref inout(typeof(this)) that) inout pure @trusted {
        self = &this;
        old = &that;
    }

    void print() const @safe {
        write(&this);
        if(old is null)
            write(" (never copied)");
        else
            write(" (last copied from ", old, " to ", self, ")");
        writeln(" in sync: ", self is &this);
    }
}

S makeS() @safe {
    S s = true;
    s.print();
    return s; // NRVO
}

void takeS(S s) @safe {
    s.print();
}

void main() @safe {
    S s = true;
    s.print();

    takeS(s);
    takeS(makeS());
}
///////////////////////////

This works on LDC, but fails on DMD with output:

7FFF765249A0 (never copied) in sync: true
7FFF765249C0 (last copied from 7FFF765249A0 to 7FFF765249D0) in sync: false
7FFF76524A00 (never copied) in sync: true
7FFF765249F0 (never copied) in sync: false

(It's weird that DMD runs the copy constructor with a destination address that isn't even the real destination.)

Anyway, thanks for helping me understand, everyone.

Reply via email to