Is it possible to deinitialize the class without calling the gc?

Adam D. Ruppe destructionator at gmail.com
Fri Aug 3 21:44:55 UTC 2018


On Friday, 3 August 2018 at 20:40:31 UTC, 12345swordy wrote:
> Did you even bother reading the links that I posted?

I did. Did you? The wikipedia page speaks at length to the 
ambiguity of the terms, including that the language construct can 
be called a destructor while the implementation methods can be 
called a finalizer, even if they do the same thing.


> Then you should know where the implementation of finalize is 
> located at, or am I looking at the wrong code here?

It is in rt/lifetime.d.

The .destroy(class) function is defined on line 560 of object.d 
in druntime/src (assuming code as of v2.081.1 release). This 
calls rt_finalize, defined on line 1422 of rt/lifetime.d (and 
note that there is a separate function right under it for 
finalizeFromGC!).

This simply forwards to rt_finalize2, defined on line 1380 in the 
same file, which does the actual work. Observe how it simply 
calls the destructors, in order, of the base class instances, 
then deletes the monitor if it is present, and copies the 
initialize memory over to make that predictable, but then nulls 
out pointer to the rtti instance for that dead object, to ensure 
it is unusable.


The one you linked to is totally unrelated. It doesn't even 
define a function called destroy nor rt_finalize. It actually 
defines a function to finalize the (manual) GC object itself!

Its run finalizers method is supposed to detect what type of 
objects are in the passed memory block, and call rt_finalize (or 
one of its variants) for them. But, of course, since it is just a 
stub implementation of the GC interface, it doesn't actually do 
that.


rt_finalize is called BY the GC or the public destroy function, 
but it is NOT part of the GC. It also does not call into any GC 
functions itself (though user-defined hooks or class destructors 
might - but note if a class dtor does, it is liable to cause the 
program to terminate with InvalidMemoryOperatorError in certain 
circumstances).

It is also called by the language almost directly in the case of 
`scope` classes, via the `_d_callfinalizer` function (defined on 
line 1238 of rt/lifetime.d, where you can see it is a simple 
forward to rt_finalize). scope classes are allocated and 
destroyed just like structs - they live on the stack and their 
destructors are called deterministically when they go out of 
scope. Explicitly not GC'd... but still calling the same 
rt_finalize function.


BTW: Generally speaking, the calls to _d_xxxx functions are 
emitted by the compiler itself, then they forward to _rt_xxx 
functions, which are the internal runtime implementations, and 
those _rt_xxx functions are also accessible through other public 
interfaces, like the .destroy() function, or Runtime.xxx static 
struct methods, etc., to give them a prettier name. Those 
prettier names are the documented ways to access it, whereas the 
_rt_ ones are subject to change without notice by druntime devs 
and the _d_ ones are subject to change by dmd devs.



So, again:

> Is it possible to deinitialize the class without calling the gc?

Yes, use the .destroy function, or a scope class (or the scoped! 
template in std.typecons, which tried to replace the built-in 
scope thing due to memory safety concerns at one point).

> Is there RecusiveDestruct function that can be called that is 
> attribute friendly?

No. Best you have is the .destroy function, which cannot work 
with the attributes because the D language definition does not 
make that possible. Child classes have independent destructors 
which do not need to adhere to the attributes of the parent class 
destructor, and moreover this cannot be detected at compile time 
when the attributes are processed - yet both must be called. 
Thus, at compile time, the destruction process must assume the 
widest possible features and the attributes do not apply.


More information about the Digitalmars-d mailing list