www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Disagreeing addresses of `this`

reply Longinus <contact lngnslnvsk.net> writes:
So my understanding is that structs have an implicit `opAssign` 
which takes its argument by value, and that it only calls the 
destructor on its own copy, but not that of the argument, which 
may be a temporary.

For example:
```d
struct S
{
     this(int x) { writeln("ctor ", &this); }
     ~this()     { writeln("dtor ", &this); }
}
void main()
{
     S s;
     writeln("main ", &s);
     s = S(42);
}
```
the result, when compiled with DMD, is
```
main 7FFF28396290
ctor 7FFF28396291
dtor 7FFF28396268
dtor 7FFF28396290
```

There are three different addresses and the ctors and dtors 
involved in the copy and `opAssign` disagree with each other.
Right now this prevents me from using `&this` in ctors & dtors 
since, as far as temporaries are concerned, this is as if a dtor 
call is being elided by the compiler.

There is this bug report about it: 
https://issues.dlang.org/show_bug.cgi?id=9666
but I'm not sure of whether the differing addresses are part of 
what's intended.
Are they?

Also are there workarounds to get the ctors and dtors to see the 
same thing, other than compiling with LDC?
May 12
parent reply Nick Treleaven <nick geany.org> writes:
On Sunday, 12 May 2024 at 13:03:35 UTC, Longinus wrote:
 So my understanding is that structs have an implicit `opAssign` 
 which takes its argument by value, and that it only calls the 
 destructor on its own copy, but not that of the argument, which 
 may be a temporary.
Not sure if it helps, but... This is the low-level code (`dmd -vcg-ast`): ```d ref system S opAssign(S p) return { (S __swap40 = void;) , __swap40 = this , (this = p , __swap40.~this()); return this; } ```
 For example:
 ```d
 struct S
 {
     this(int x) { writeln("ctor ", &this); }
     ~this()     { writeln("dtor ", &this); }
 }
 void main()
 {
     S s;
     writeln("main ", &s);
     s = S(42);
 }
 ```
 the result, when compiled with DMD, is
 ```
 main 7FFF28396290
`main.s`
 ctor 7FFF28396291
Temporary `S(42)` is constructed on main's stack, passed as argument `p` to `opAssign`. Then: * `main.s` is bit-copied to `__swap40`. * `p` is then bit-copied to `main.s`.
 dtor 7FFF28396268
`__swap40.~this()` inside `opAssign`.
 dtor 7FFF28396290
`main.s.~this()` at the end of `main`.
May 12
parent reply Longinus <contact lngnslnvsk.net> writes:
On Sunday, 12 May 2024 at 21:09:33 UTC, Nick Treleaven wrote:
 * `p` is then bit-copied to `main.s`.
Yeah this is the last time anything is done with `p`. Its destructor does not get called. I understand that avoiding this further copy may be an optimisation, but while I can have a dtor deal with an uninitialised object (by doing no-op), an initialised object not having its dtor called, that I don't know how to work with. My current work-around is to simply _not_ use temporaries, but it's awkward and I don't know how to make the compiler warn on their usage. (For reference: yes, I'm literally having the ctor/dtor write `&this` in places; so this is introducing dangling pointers) Thanks for looking into it.
May 13
parent Max Samukha <maxsamukha gmail.com> writes:
On Tuesday, 14 May 2024 at 02:01:10 UTC, Longinus wrote:
 On Sunday, 12 May 2024 at 21:09:33 UTC, Nick Treleaven wrote:
 * `p` is then bit-copied to `main.s`.
Yeah this is the last time anything is done with `p`. Its destructor does not get called. I understand that avoiding this further copy may be an optimisation, but while I can have a dtor deal with an uninitialised object (by doing no-op), an initialised object not having its dtor called, that I don't know how to work with.
But the destructor does get called on each initialized object. `s` is moved (not copied) into the uninitialized `__swap40` and then the destructor is called on `__swap40`. Then `p` is moved into `s` and the destructor is called on `s` at `main`'s exit. Note that D mandates all struct objects be movable.
May 13