Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Destructors

A destructor runs when an object goes away. It is where an object gives back what it holds: memory, a file, a lock. Because the compiler calls it for you, the clean-up cannot be forgotten on any path out of a scope.

type Tracer
    declare constructor( byref label as ustring )
    declare destructor( )
    label as ustring
end type

constructor Tracer( byref label as ustring )
    this.label = label
    print "  + "; label
end constructor

'' The destructor runs when the object goes away.
destructor Tracer( )
    print "  - "; label
end destructor

sub Work( )
    dim as Tracer t = Tracer( "local to Work" )
    print "  working"
end sub                             '' t is destroyed here

print "start"
dim as Tracer whole = Tracer( "program-wide" )

print "a scope:"
scope
    dim as Tracer first = Tracer( "first" )
    dim as Tracer second = Tracer( "second" )
end scope                           '' last created, first destroyed

print "a procedure:"
Work( )

print "a loop:"
for i as int32 = 1 to 2
    dim as Tracer lap = Tracer( "pass " & i )
next                                '' once per pass

print "a temporary:"
var size = len( Tracer( "temporary" ).label )
print "  its label had"; size; " characters"

print "end"

Output

start
  + program-wide
a scope:
  + first
  + second
  - second
  - first
a procedure:
  + local to Work
  working
  - local to Work
a loop:
  + pass 1
  - pass 1
  + pass 2
  - pass 2
a temporary:
  + temporary
  - temporary
  its label had 9 characters
end
  - program-wide

An object is destroyed when the block that declared it ends:

Declared inDestroyed
a scope or other blockat its end
a procedurewhen the procedure returns
a loop bodyat the end of every pass
an expression, as a temporarywhen the statement finishes
the program's top levelwhen the program ends

Objects in one block are destroyed in reverse order of creation: second before first. Something created later may depend on something created earlier, never the other way round, so this order is always safe.

A type has one destructor, with no parameters. If you do not write one, the compiler still destroys every field: a field that is itself an object gets its destructor, and a ustring field frees its text, without your help.

Objects made with new live until you delete them; they are covered in Memory and Resources. When a type is meant to be destroyed through a pointer to its base type, its destructor must be virtual: see Virtual destructors.

Activities

  1. Add a third Tracer to the scope and predict the order of the lines.
  2. Put exit for in the loop on the first pass. Does lap still get its destructor?