PlStream can be used to get a stream from a Prolog term, 
or to lock the stream so that other threads cannot interleave their 
output. With either usage, PlStream is a RAII 
class that ensure the matching PL_release_stream() is done, and 
also handles some subtle problems with C++ exceptions.
The methods are:
PlStream 
object to an invalid stream (see PlStream::check_stream()).IOSTREAM*, PlStream 
is implicitly converted to IOSTREAM*.PlStream object contains a valid stream and throws an 
exception if it doesn't. This is used to ensure that PlStream::release() 
hasn't been called.
Most of the stream I/O functions have corresponding methods in PlStream. 
For example, Sfprintf() corresponds to
PlStream::printf(). PlStream::seek() and PlStream::tell() 
call
Sseek64() and Stell64() instead of long (they 
are also deprecated: PlStream::seek64() and PlStream::tell64() 
are preferred).
The C interface to stream I/O doesn't raise a Prolog error when 
there's a stream error (typically indicated by a -1 return code). 
Instead, the error sets a flag on the stream and
PL_release_stream() creates the error term. The
PlStream destructor calls PL_release_stream(); but 
it's a fatal error in C++ to raise an exception in a destructor if the 
destructor is invoked by stack-unwinding due to another exception, 
including the pseudo-exceptions PlFail and
PlExceptionFail.
To get around this, the various stream I/O functions have wrapper 
methods in the PlStream class that check for an error and 
call PlStream::release() 
to create the Prolog error, which is thrown as a C++ error.
The destructor calls PlStream::release(), which throws a C++ exception if there is a stream error. This is outside the destructor, so it is safe - the destructor checks if the stream has been released and does nothing in that situation.
The following two code examples do essentially the same thing:
PREDICATE(name_arity, 1)
{ PlStream strm(Scurrent_output);
  strm.printf("name = %s, arity = %zd\n", A1.name().as_string().c_str(), A1.arity());
  return true;
}
PREDICATE(name_arity, 1)
{ PlStream strm(Scurrent_output);
  try
  { strm.printf("name = %s, arity = %zd\n", A1.name().as_string().c_str(), A1.arity());
  } PREDICATE_CATCH({strm.release(); return false;})
  return true;
}
If you write the code as follows, using Sfprintf() directly, it is possible that a fatal exception will be raised on an I/O error:
PREDICATE(name_arity, 1)
{ PlStream strm(Scurrent_output);
  Sfprintf(strm, "name = %s, arity = %zd\n", A1.name().as_string().c_str(), A1.arity());
  return true;
  // WARNING: the PlStream destructor might throw a C++
  //          exception on stack unwinding, giving a fatal
  //          fatal runtime exception.
}
If you don't use these, and want to throw an exception if there's an 
error, the following code works because PlStream (and the 
underlying PL_acquire_stream()) can be called recursively:
{ PlStream strm(...);
  strm.release();
}