Move Constructors - Converting Lvalues to Rvalues

Timon Gehr timon.gehr at gmx.ch
Thu Oct 3 00:57:44 UTC 2024


On 10/3/24 02:42, Timon Gehr wrote:
> Later if you add a move constructor, it will automatically select that 
> as the appropriate choice.

About this, actually it might not do so with `-preview=rvaluerefparam` 
sometimes because the rvalue-ness of the argument is not known statically.

Basically, let's assume S has both a copy constructor and a move constructor

```d
void byref(ref S s){ // ABI: passed by reference, caller cleanup
     S t = s; // calls copy constructor
     // ...
}
```

```d
void byval(S s){ // ABI: passed by value, callee cleanup
     S t = s; // calls move constructor (with DIP1040)
     // ...
}
```

```d
void bymove(@move S s){ // ABI: passed by reference, callee cleanup
     S t = s; // calls move constructor (with DIP1040)
     // ...
}
```

```d
byref(s); // passes &s, move constructor called 0 times overall

byval(move(s)); // moves s, has to call move constructor, move 
constructor called twice overall

bymove(s); // semantically moves, actually passes &s. move constructor 
is only called once, in the function body
```

Of course, you can do:

```d
void explicitmove(ref S s){
     S t = move(s);
}
```

That would have similar semantics in practice as the `bymove` (though 
the caller will always call the destructor with `explicitmove`, while 
with `bymove`, the caller may be able to elide it). However, you had to 
be explicit about it. It is not true that the code is upgraded for free, 
because `byref` actually assumes that the caller is responsible for 
cleaning up the parameter. This is true whether it is an rvalue or an 
lvalue.



More information about the Digitalmars-d mailing list