Thread overview
scope(exit) and destructor prioity
Sep 18, 2017
Sasszem
Sep 18, 2017
Jerry
Sep 18, 2017
Sasszem
Sep 18, 2017
Eugene Wissner
Sep 18, 2017
Moritz Maxeiner
September 18, 2017
I'm currently working on a project and for that I've created a thin OO-wrapper on top of derelict-sdl. However, when I close my app, the program terminates with a segfault. I've managed to track down the source, and found that the destructors of my objects are called AFTER the scope(exit) statements. This causes my program to call TTF_CloseFont() after TTF_Quit(), resulting in a segfault.
My questions:
 - Can I force D to call the destructors BEFORE the scope(exit) statements?
 - If not, is there a way around?
September 18, 2017
On Monday, 18 September 2017 at 20:26:05 UTC, Sasszem wrote:
> I'm currently working on a project and for that I've created a thin OO-wrapper on top of derelict-sdl. However, when I close my app, the program terminates with a segfault. I've managed to track down the source, and found that the destructors of my objects are called AFTER the scope(exit) statements. This causes my program to call TTF_CloseFont() after TTF_Quit(), resulting in a segfault.
> My questions:
>  - Can I force D to call the destructors BEFORE the scope(exit) statements?
>  - If not, is there a way around?

It's called inbetween the destructors of wherever you put the scope(exit).

import std.stdio;

struct De
{
	~this() { writeln("De"); }
}

void main()
{
	De a;
	scope(exit) writeln("scope exit");
	De b;
}


Output:
De
scope exit
De
September 18, 2017
On Monday, 18 September 2017 at 20:30:20 UTC, Jerry wrote:
> On Monday, 18 September 2017 at 20:26:05 UTC, Sasszem wrote:
>>  [...]
>
> It's called inbetween the destructors of wherever you put the scope(exit).
>
> import std.stdio;
>
> struct De
> {
> 	~this() { writeln("De"); }
> }
>
> void main()
> {
> 	De a;
> 	scope(exit) writeln("scope exit");
> 	De b;
> }
>
>
> Output:
> De
> scope exit
> De

If I write "auto a = new De()", then it calls the scope first, no matter where I place it.
September 18, 2017
On Monday, 18 September 2017 at 20:55:21 UTC, Sasszem wrote:
> On Monday, 18 September 2017 at 20:30:20 UTC, Jerry wrote:
>> On Monday, 18 September 2017 at 20:26:05 UTC, Sasszem wrote:
>>>  [...]
>>
>> It's called inbetween the destructors of wherever you put the scope(exit).
>>
>> import std.stdio;
>>
>> struct De
>> {
>> 	~this() { writeln("De"); }
>> }
>>
>> void main()
>> {
>> 	De a;
>> 	scope(exit) writeln("scope exit");
>> 	De b;
>> }
>>
>>
>> Output:
>> De
>> scope exit
>> De
>
> If I write "auto a = new De()", then it calls the scope first, no matter where I place it.

If I write "auto a = new De()" I have the same behaviour. If I have "auto b = new De()" aswell, then yes, destructors are called after scope exit.
Because you allocate on the heap with new, the destructor isn't called at the end of the scope at all. It is called later by the GC.

Try to put variable declarations with destructor after "scope exit" or destroy them manually with "destroy(a)".

See https://dlang.org/spec/statement.html#scope-guard-statement for order of calling destructors at the end of scope.
September 18, 2017
On Monday, 18 September 2017 at 20:55:21 UTC, Sasszem wrote:
>
> If I write "auto a = new De()", then it calls the scope first, no matter where I place it.

Because with `new`
a) your struct object is located on the heap (and referred to by pointer - `De*`) instead of the stack (which means no destructors for it are called at function scope end), and
b) the lifetime of your struct object is determined by D's garbage collector, which may or may not eventually collect it, finalizing it in the process (calling the destructor, as D doesn't separate finalizers and destructors a.t.m.).
In your case, it sounds like the GC collection cycle that (in the current implementation) occurs just before druntime shutdown collects it.
I highly recommend reading The GC Series on the D blog [1].

[1] https://dlang.org/blog/the-gc-series/