2.5.7.3 The life of a PlBlob
In this section, the blob is of type MyBlob
, a subclass
of PlBlob
. (Example code is given in section
2.5.7.5)
A blob is typically created by calling a predicate that does the following:
- Creates the blob using
auto ref = std::unique_ptr<PlBlob>(new MyBlob>(...))}
or
auto ref = std::make_unique<MyBlob>(...);
- After the fields of the blob are filled in:
return PlTerm::unify_blob(&ref);
If unification fails or throws an exception, the object is automatically freed and its destructor is called.
If make_unique() was used to create the pointer, you need to call PlTerm::unify_blob() as follows, because C++'s type inferencing can't figure out that this is a covariant type:
std::unique_ptr<PlBlob> refb(ref.release()); // refb now "owns" the ptr - from here on, ref == nullptr return A2.unify_blob(&refb);
If unification succeeds, Prolog calls:
- PlBlobV<MyBlob>acquire(), which calls
- MyBlob::acquire(), which sets the field MyBlob::symbol_,
which is usually accessed using the method MyBlob::symbol_term().
If this all succeeds, PlTerm::unify_blob(ref)
calls
ref->release()
to pass ownership of the blob to Prolog (when the blob is eventually garbage collected, the blob's destructor will be called).
At this point, the blob is owned by Prolog and may be freed by its
atom garbage collector, which will call the blob's destructor (if the
blob shouldn't be deleted, it can override the the PlBlob::pre_delete()
method to return false
).
Whenever a predicate is called with the blob as an argument (e.g., as A1),
the blob can be accessed by
PlBlobv<MyBlob>::cast_check(A1.as_atom())
.
Within a method, the Prolog blob can be accessed as a term (e.g., for
constructing an error term) using the method MyBlob::symbol_term().
This field is initialized by the call to PlTerm::unify_blob();
if
MyBlob::symbol_term() is called before a successful call to
PlTerm::unify_blob(), MyBlob::symbol_term()
returns a
PlTerm_var
.
When the atom garbage collector runs, it frees the blob by first calling the release() callback, which does delete, which calls the destructor MyBlob::~MyBlob(). Note that C++ destructors are not supposed to raise exception; they also should not cause a Prolog error, which could cause deadlock unless the real work is done in another thread.
Often it is desired to release the resources before the garbage collector runs. To do this, the programmer can provide a “close” predicate that is the inverse of the “open” predicate that created the blob. This typically has the same logic as the destructor, except that it can raise a Prolog error.