About ref used for performance reasons with struct

kinke noone at hotmail.com
Tue Feb 12 14:19:30 PST 2013


On Tuesday, 12 February 2013 at 13:34:10 UTC, kinke wrote:
> I think the intended move semantics (byval passing for small 
> structs w/o postblit constructor/destructor, otherwise byref) 
> are only really safe if the argument is an rvalue - the rvalue 
> is guaranteed not to be used after the call, so potential 
> modifications are not visible for the caller, and the rvalue is 
> guaranteed not to be used simultaneously in another thread. 
> Certain lvalue cases could be optimized as well, e.g., if the 
> lvalue is a private variable of the caller (local variable or 
> parameter) AND is not used after the call.

Sorry, please discard these lvalue cases, they aren't safe, i.e., 
analog to my earlier example:

---
struct BigStruct { long a, b, c; }

long foo(const BigStruct s, ref long c)
{ // s is the callee's copy of the argument
   c = s.a + s.b + s.c;
   return s.c;
}
long foo_ref(const ref BigStruct s, ref long c)
{ // s is a reference to the caller's argument
   c = s.a + s.b + s.c;
   return s.c;
}

BigStruct s = { 1, 2, 3 };
long r1 = foo(s, s.c);
assert(s.c == 6 && r1 == 3); // returns callee's s.c
s.c = 3; // reset
long r2 == foo_ref(s, s.c); // returns caller's s.c
assert(s.c == 6 && r2 == 6);
---

So aliasing issues (the caller's argument is modified indirectly 
via another parameter/global variable) are able to break code 
when passing _any_ lvalue transparently byref, even if it's not 
used afterwards. So only rvalues are really safe for move 
semantics, i.e., they can't be modified by another thread or 
indirectly by the callee via aliasing AND modifications are not 
visible to the caller after the call.


More information about the Digitalmars-d mailing list