On Monday, 3 June 2013 at 16:00:58 UTC, Ali Çehreli wrote:
On 06/03/2013 05:26 AM, Saurabh Das wrote:
> Thank you @Ali and @Jonothan!
>
> So essentially since I will be storing a pointer,
Telemetry!(T) is NOT safe
> to use only with structs in general.
>
> If I have something like:
>
> struct UsefulStruct2
> {
> this(this) @disable;
> this(UsefulStruct2) @disable;
> this(ref const(UsefulStruct2)) @disable;
> ref UsefulStruct2 opAssign(UsefulStruct2) @disable;
> ref UsefulStruct2 opAssign(ref const(UsefulStruct2))
@disable;
>
> int importantValue;
> auto tel1 = Telemetry!int(importantValue);
> }
>
> Does that ensure that UsefulStruct2 is not relocateable and
thus I can
> safely store a pointer to importantValue?
No. The compiler can still move a struct by blit (bit level
transfer). Blit is based on good old memcpy. For a "copy",
post-blit is for making corrections after the fact. On the
other hand, the programmer cannot interfere if it is a "move".
For example, rvalues are moved, e.g. to an array element as in
the following example:
import std.stdio;
import std.array;
struct UsefulStruct2
{
this(this) @disable;
this(UsefulStruct2) @disable;
this(ref const(UsefulStruct2)) @disable;
ref UsefulStruct2 opAssign(UsefulStruct2) @disable;
ref UsefulStruct2 opAssign(ref const(UsefulStruct2))
@disable;
int importantValue;
int * p;
}
UsefulStruct2 makeObject(int i)
{
UsefulStruct2 u;
u.importantValue = i;
u.p = &u.importantValue; // <-- self-referencing
return u;
}
void main()
{
auto arr = [ makeObject(1) ];
assert(arr.front.p != &arr.front.importantValue); //
PASSES!
}
> If not, what constraints do I need to add to my classes to
ensure that I
> don't run into subtle bugs when structs relocate?
As you see, @disable is cripling and not a solution for this.
As far as I know, the only option is to observe this rule.
I agree with you that a struct may become self-referencing,
unknowingly and indirectly through members of other types.
Ali
You can get around this limitation by making a wrapper struct
which uses special values to represent pointers which point
within the containing struct, and does the conversion
automatically when you dereference it.