|Did you know ...||Search Documentation:|
|Discussion of the sample PlBlob code|
PL_blob_tstructure with the wrapper functions and flags set to
PL_BLOB_NOCOPY. It should be declared outside the
PlBlobclass and should not be marked
const- otherwise, a runtime error can occur.13The cause of the runtime error is not clear, but possibly has to do with the order of initializing globals, which is unspecified for C++.
MyBlobstruct is a subclass of
PlBlob. See below for a discussion of the default behaviors.
MyBlobcontains a pointer to a
MyConnectionobject and keeps a copy of the connection's name. The
MyConnectionobject is handled by a
std::unique_ptrsmart pointer, so that it is automatically freed when the
MyBlobobject is freed.
MyBlobclass must not provide a copy or move constructor, nor an assignment operator (PlBlob has these as
delete, so if you try to use one of these, you will get a compile-time error).
PlBlob’s constructor sets
blob_t_to a pointer to the
my_blobdefinition. This is used for run-time consistency checking by the various callback functions and for constructing error terms (see PlBlob::symbol_term()).
PlBlob’s acquire() is called by PlBlobV<MyBlob>::awcuire() and fills in the
MyBlobmust not override this - it is not a virtual method.
MyConnectionobject. If this fails, an exception is thrown. The constructor then calls MyConnection::open() and throws an exception if that fails. (The code would be similar if instead the constructor for
MyConnectionalso did an open and threw an exception on failure.)
PL_BLOB_SIZEis boilerplate that defines a blob_size_() method that is used when the blob is created.
throw PlUnknownError("..."), that will try to create a Prolog term, which will crash because the environment for creating terms is not available. Because there is no mechanism for reporting an error, the destructor prints a message on failure (calling PL_warning() would cause a crash).
PlBlob::close() calls MyConnection::close() and then frees the
object. Error handling is left to the caller because of the possibility
that this is called in the context of garbage collection. It is not
necessary to free the
MyConnection object here - if it is
not freed, the
destructor would free it.
The _b_data argument is of type
- this is cast to
const MyBlob* using a
static_cast. This is safe because Prolog guarantees that
PlBlobV<PlBlob>::compare() will only be called if both
blobs are of the same type.
The flags argument is the same as given to PlBlobV<PlBlob>::write(),
which is a bitwise or of zero or more of the
flags that were passed in to the caling PL_write_term() (defined
flags do not have the
PL_WRT_NEWLINE bit set, so
it is safe to call PlTerm::write() and there is no need for writing a
If anything in PlBlob::write_fields() throws a C++ exception, it will be caught by the calling PlBlobV<PlBlob>::write() and handled appropriately.
std::unique_ptr<PlBlob>()creates a MyBlob that is deleted when it goes out of scope. If an exception occurs between the creation of the blob or if the call to unify_blob() fails, the pointer will be automatically freed (and the
MyBlobdestructor will be called).
If PlTerm::unify_blob() is called with a pointer to a
std::unique_ptr, it takes ownership of the object by
calling std::unique_ptr<PlBlob>::release(). This sets ref
nullptr, so any attempt to use ref after a
successful call to PlTerm::unify_blob() will be an error.
If you wish to create a
MyBlob object instead of a
PlBlob object, a slightly different form is used:
auto ref = std::make_unique<MyBlob>(...); ... std::unique_ptr<PlBlob> refb(ref.release()); PlCheckFail(A2.unify_blob(&refb)); return true;
MyBlobpointer using the PlBlobV<MyBlob>::cast_ex() function, which will throw a
type_errorif the argument isn't a blob of the expected type.