Programming in D p288. Destructor called too many times.
H. S. Teoh
hsteoh at qfbox.info
Mon Feb 9 21:48:55 UTC 2026
On Mon, Feb 09, 2026 at 08:19:26PM +0000, Brother Bill via Digitalmars-d-learn wrote:
> The destructor runs too many times. I would expect it to run just
> once. What am I doing "wrong"?
You are doing nothing wrong. But you may not have realized the implicit
copies of your Duration struct, each of which need to be individually
destructed.
Remember that a struct is a by-value type; this means that passing it to
a function creates a copy and hands that copy over to the function. In
this case, the call to writeln would create a copy of the duration,
which would get destructed after writeln returns. Furthermore, writeln
itself may need to pass its arguments to various helper functions. Each
time this happens, a new copy of the duration is made, which is then
destroyed accordingly when it goes out of scope. From your output, it
looks like it gets copied 4-5 times in the process of writeln turning it
into a human-readable string.
Generally, if you're using structs correctly, this copying is fast,
harmless and does not cause any problems (except perhaps for calling the
dtor more often than you expected because of the implicit copies you
didn't realize was happening).
But if you *must* control exactly when something gets copied, you should
consider using a by-reference type, like a class or a struct wrapper
around a pointer / reference type. Keep in mind, though, that reference
types come with their own caveats, and having too many levels of
indirection may not be the best thing to do in some cases.
--T
> source/app.d
> ```
> import std.stdio : writeln;
> import std.string : format;
>
> void main()
> {
> bool aCondition = true;
>
> if (aCondition)
> {
> auto duration = Duration(7, 30, 15);
> writeln("Duration is: ", duration);
> } // ← The destructor is executed for 'duration' at this point as duration
> goes out of scope.
> }
>
> struct Duration
> {
> int hours;
> int minutes;
> int seconds;
>
> this(in int h, in int m, in int s)
> {
> writeln("Creating Duration: ", h, ":", m, ":", s);
> hours = h;
> minutes = m;
> seconds = s;
> }
>
> ~this()
> {
> writeln("Destroying Duration: ", hours, ":", minutes, ":", seconds);
> }
>
> string toString() const
> {
> return format("%02d:%02d:%02d", hours, minutes, seconds);
> }
> }
> ```
>
> Console output:
> ```
> Creating Duration: 7:30:15
> Duration is: 07:30:15Destroying Duration: 7:30:15
> Destroying Duration: 7:30:15
>
> Destroying Duration: 7:30:15
> Destroying Duration: 7:30:15
> Destroying Duration: 7:30:15
> ```
--
Hey, anyone can ignore me and go ahead and do it that way. I wish you the best of luck -- sometimes us old coots are dead wrong -- but forgive me if I'm not going to be terribly sympathetic if you ignore my advice and things go badly! -- Walter Bright
More information about the Digitalmars-d-learn
mailing list