2.5.7.4 C++ exceptions and blobs
When a blob is used in the context of a PREDICATE()
macro, it can raise a C++ exception (PlFail
or PlException
)
and the
PREDICATE() code will convert
the exception to the appropriate Prolog failure or error; memory
allocation exceptions are also handled.
Blobs have callbacks, which can run outside the context of a PREDICATE(). Their exception handling is as follows:
- void PlBlob::acquire()
- , which is called from PlBlobV<MyBlob>::acquire(), can throw a C++ exception. The programmer cannot override this.
- int PlBlob::compare_fields(const PlBlob *_b)
- , which is called from PlBlobV<MyBlob>::compare(), should not throw an exception. A Prolog error won't work as it uses “raw pointers” and thus a GC or stack shift triggered by creating the exception will upset the system.
- bool PlBlob::write_fields(IOStream *s, int flags)
- , which is called from PlBlobV<MyBlob>::write(), can throw an exception, just like code inside a PREDICATE(). In particular, you can wrap calls to Sfprintf() in PlCheckFail(), although the calling context will check for errors on the stream, so checking the Sfprintf() result isn't necessary.
- void PlBlob::PlBlob::save(IOStream *fd)
- can throw a C++ exception, including PlFail().
- PlAtom PlBlob::PlBlob::load(IOSTREAM *fd)
- can throw a C++ exception, which is converted to a return value of
PlAtom::null
, which is interpreted by Prolog as failure. - bool PlBlob::PlBlob::pre_delete()
- , which is called from PlBLobV<MyBLOB>::release(),
can return
false
(or throw aPlException
orPlExceptinFailBase
, which will be interpreted as a return value offalse
), resulting in the blob not being garbage collected, and the destructor not being called. Note that this doesn't work well with final clean-up atom garbage collection, which disregards the return value and also doesn't respect the ordering of blob dependencies (e.g., if an iterator blob refers to a file-like blob, the file-like blob might be deleted before the iterator is deleted).This code runs in the
gc
thread. The only PL_*() function that can safely be called are PL_unregister_atom() (which is what PlAtom::unregister_ref() calls).