PL_blob_t
structure with the wrapper functions and flags
set to PL_BLOB_NOCOPY
. It should be declared outside the PlBlob
class 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++.
MyBlob
struct is a subclass of PlBlob
.
See below for a discussion of the default behaviors.
MyBlob
contains a pointer to a MyConnection
object and keeps a copy of the connection's name. The MyConnection
object is handled by a std::unique_ptr
smart pointer, so
that it is automatically freed when the MyBlob
object is
freed.
PlBlob
constructor.
MyBlob
class 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_blob
definition. 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 symbol
field. MyBlob
must not
override this - it is not a virtual method.
MyConnection
object. 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 MyConnection
also did an open and threw an exception on failure.)
PL_BLOB_SIZE
is 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
std::unique_ptr<MyConnection>
’s
destructor would free it.
0
("equal").
The _b_data argument is of type const PlBlob*
- 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 PL_WRT_*
flags that were passed in to the caling PL_write_term() (defined
in SWI-Prolog.h
). The
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
trailing newline.
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
MyBlob
destructor 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
to 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;
MyBlob
pointer using the
PlBlobV<MyBlob>::cast_ex() function, which will throw a
type_error
if the argument isn't a blob of the expected
type.