Did you know ... | Search Documentation: |
Discussion of the sample PlBlob code |
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.20The 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>::acquire()
and fills in the symbol_
field. MyBlob
must
not override this - it is not a virtual method. The symbol_
field can be accessed by PlBlob::symbol_term().
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.
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).
PlTerm::unify_blob()
is called with a pointer to a
std::unique_ptr
, which takes ownership of the object by
calling std::unique_ptr<PlBlob>::release() and
passes the pointer to Prolog, which then owns it. This also sets ref
to nullptr
, so any attempt to use ref after a
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.