try … except
try
Value := StrToInt(Text);
Result := 100 div Value;
except
on E: EConvertError do
ShowMessage('Not a number: ' + E.Message);
on EDivByZero do
Result := 0;
on E: Exception do
begin
Log(E.ClassName + ': ' + E.Message);
raise; { raise the same exception again }
end;
else
{ any other kind of exception, only without an on clause }
end;
The statements between try and except run; if one raises an
exception, the rest of them are skipped and the handlers are tried in order. An
on clause names an exception class (and optionally a variable bound to the
object) and matches that class and its descendants. Statements directly after
except (with no on) handle every exception. If no handler matches,
the exception goes on to the caller. The exception object is freed when the handler ends,
unless it is re-raised.
try … finally
Stream := TFileStream.Create(Name, fmOpenRead);
try
Process(Stream);
finally
Stream.Free; { runs whether Process worked or raised }
end;
The statements after finally run however the statements after
try end: normally, by an exception, or by Exit, Break,
Continue or goto out of the block. The idiom is to create a resource, then
try straight after, and release it in finally. An exception
that passes through goes on afterwards.
raise
raise Exception.Create('Something went wrong');
raise EInvalidInput.CreateFmt('Bad value %d', [N]);
raise; { inside an except block: re-raise }
raise EFoo.Create('x') at ReturnAddress; { set the reported address }
raise with an object creates the exception; raise alone in an
except part raises the current one again. at Address gives the
address the error is reported to be at. An exception is an object of a class derived
from Exception, which has a Message property, a constructor
Create(Msg), CreateFmt(Format, Args) and
CreateRes, and HelpContext.
The exception classes
| Class | Raised for |
|---|---|
Exception | the root of the tree |
EAbort | Abort, which stops an operation quietly |
EConvertError | StrToInt, StrToFloat and other conversions of bad text |
EInOutError | file errors (with {$I+}), with ErrorCode |
EOutOfMemory, EInvalidPointer | the heap ran out, or a bad pointer was freed |
EIntError: EDivByZero, ERangeError, EIntOverflow | integer division by zero, a range check ({$R+}), an overflow check ({$Q+}) |
EMathError: EZeroDivide, EInvalidOp, EOverflow, EUnderflow | floating point errors |
EAccessViolation | a bad memory address (the operating system fault) |
EInvalidCast, EVariantError, EAssertionFailed | a failed as, a bad variant conversion, a failed assert |
EListError, EStreamError, EComponentError | errors of the Classes unit |
Run-time errors and I/O results
- Turbo Pascal and ISO programs have no exceptions: a fault ends the program with a message
Runtime error N at address. The number is the exit code: 2 file not found, 3 path not found, 4 too many open files, 5 file access denied, 100 disk read error, 101 disk write error, 106 invalid numeric format, 200 division by zero, 201 range check, 202 stack overflow, 203 heap overflow, 205 floating point overflow, 207 invalid floating point operation, and so on. {$I-}turns off the automatic check of input and output. After a file operationIOResultreturns the error code (0 for none) and must be read to clear it, and it is the way to test whether a file exists or can be opened in code without exceptions.Halt(Code)ends the program at once with an exit code;RunError(Code)ends it with a run-time error;ExitProc(Turbo Pascal) orfinalizationsections andAddExitProcrun on the way out.ExitCodeandErrorAddrhold the end state.- Delphi and Free Pascal turn most run-time errors into exceptions of the classes above.
ExceptObjectandExceptAddrgive the current exception inside a handler.
Pointers and dynamic memory
var
P: ^Integer;
Buf: Pointer;
begin
New(P); { allocate an Integer on the heap }
P^ := 42;
Dispose(P); { free it }
GetMem(Buf, 1024); { allocate raw bytes }
FillChar(Buf^, 1024, 0);
ReallocMem(Buf, 2048);
FreeMem(Buf);
end;
New(P)allocates the size ofP^andDispose(P)frees it, finalising managed fields.GetMem(P, Size),ReallocMemandFreeMem(P)work on bytes. Anilpointer points at nothing; using it raises an access violation.InitializeandFinalizeprepare and release managed contents.MaxAvailandMemAvail(Turbo Pascal) report free memory, andGetHeapStatus,GetFPCHeapStatus(Delphi, Free Pascal) fill a record with heap figures.MarkandRelease(Turbo Pascal, UCSD) free everything allocated since the mark.- The heap manager can be replaced:
SetMemoryManagerin Delphi and Free Pascal; Delphi has used FastMM since Delphi 2006 as its default; Free Pascal’s-ghoption turns on theheaptrcunit that reports leaks.
Who frees what
| Kind of value | Lifetime |
|---|---|
| Integer, real, boolean, enumeration, set, static array, record | Lives in the variable that holds it; no freeing. |
AnsiString, UnicodeString, dynamic array, Variant, interface reference | Reference counted: the compiler adds and removes references, and frees the data when the last goes away. Assign nil or '', or let the variable go out of scope. |
| Class instance | Freed by hand with Free (or FreeAndNil). A component’s owner frees it when the owner is freed. Delphi’s mobile compilers before 10.4 reference counted classes too (ARC), with [Weak] and [Unsafe] to control it. |
New or GetMem memory | Freed by hand with Dispose or FreeMem. |
| Object (Turbo Pascal) on the heap | Dispose(P, Done). |
Low-level access
@XandAddr(X)take addresses;Ptr(Segment, Offset)(DOS) andPtr(Address)make a pointer from a number;SegandOfssplit a DOS far pointer;Mem[Seg:Ofs],MemWandMemL(Turbo Pascal) read and write memory directly;Port[N]andPortW[N]read and write I/O ports.- Typed pointer arithmetic and indexing need
{$POINTERMATH ON}, or are allowed onPChar;Inc(P)steps by the size of the target. absolutevariables overlay an address or another variable.Move,FillChar,CompareByteandCopywork on blocks of memory.