On Tuesday, 12 November 2013 at 20:29:13 UTC, Dicebot wrote:
On Tuesday, 12 November 2013 at 20:15:02 UTC, Florian wrote:
I played around a little and figured out, that destructors in D work quite similarily to destructors in C++. They are invoked, after the members of the instance being destructed have been destroyed themselfes (or at least have been brought into an invalid state). Therefore, these members cannot be accessed savely from inside the destructor.

What made you think so? It must be other way around. Destructor is expected to release resources held by object, it is necessary that those resources are still valid at destructor call point. It would have been completely against the mode of operations of garbage collector.

Let me explain this by discussing the example below. I created method stubs, which write single lines to the console, so it is quite easy to follow the control flow.

The main method creates an instance of a type "Session", which itself has a member of type "Connection". Let us assume, that I want to properly shutdown the "Connection" instance by invoking its methods, when the "Session" is torn down. The example below prints the following output:
    ~Connection
    ~Session
    segmentation fault
This means, the destructor of "Connection" is invoked *BEFORE* the destructor of "Session" is called. This yields to an invalid reference for the call of the shutdown() method, leading to the segmentation fault. Of course, in a scenario as simple as that, it would be possible to move the shutdown() sequence into the destructor of the "Connection" class. However, doing so is not desirable. Just picture, that we want to set some timeout parameters or the like for the shutdown depending on the state of the "Session". This would become really messy. And be assured, I have a more complex scenario, where I definitely want to invoke methods on memeber instances when an instance is destroyed. I am convinced there is a reason for finalizing objects like Java, C# and managed C++ do.

Example:

import std.stdio;

class Connection {
        this() { }
        void shutdown() { writeln("shutdown"); }
        ~this() { writeln("~Connection"); }
}

class Session {
        Connection connection;
        this() { connection = new Connection(); }
        ~this() {
                writeln("~Session");
                connection.shutdown();  // -> segmentation fault
        }
}

void main() { auto session = new Session(); }

Reply via email to