Possible bug in libstdc++ 2.90.8

Benjamin Kosnik bkoz@redhat.com
Tue Aug 15 11:42:00 GMT 2000


Hi Maurizio.

> I am using libstdc++ 2.90.8 together with g++ 2.95.2 .  I have problems
> with my code, because a class that I define inherits from streambuf and
> cannot call streambuf::sync(); streambuf's sync() is inherited from
> basic_streambuf's sync() that is declared 'protected' and cannot be called
> from a class derived from a derived class.

... just use the public methods, pubsync() instead. Pretty 
straightforward bug fix....

> A simplified version of the code I am using is in the attachment; the code
> itself compiles and links with Kuck and Associates Inc. (KAI) KCC compiler
> after having substituted a couple of int with unsigned int in the
> procedure declaration.

... also a bit of type non-standardization, which I fixed in the edited 
copy of your code below. The edited code works correctly for me with CVS 
libstdc++-v3,.

> I am also (dis)pleased to announce that the perl script at
> http://sources.redhat.com/ to submit bug reports does not work for me :-(

? Seems to work for me. Can you provide more detail?

thanks,
benjamin

// This toy example (based on code written under the GNU GPL by
// Dietmar Kuehl, http://www.informatik.uni-konstanz.de/~kuehl/ ) shows
// how to define an ostream-like class in such a way that everything
// that will be written to the stream goes both to the standard output
// and to a disk log file.

#include <iostream>
#include <fstream>
#include <stdexcept>

using namespace std;

// The important part of this file is a class mySbuf, derived from the
// class streambuf defined in <iostream>; streambuf defines an
// interface used by [i/o]streams to read bytes from an external
// representation and to write bytes to an external representation.
// The actual handling of the external representation is implemented
// in classes derived from streambuf; in our case the "external
// representation" is a wrapper class that will send every received
// byte to two streams (only _output_ streams are considered).  An
// internal flag allows to inhibit output to the log file; methods to
// access and modify that flag are provided.

class mySbuf : public streambuf {
private:
  streambuf *scr_sb_;           // The streambuf associated with cout;
  streambuf *log_sb_;           //   the one associated with the log file;
  bool       log_;              //     a flag to inhibit log file writing.

#if 0
  int overflow(int);            // Pure virtual methods inherited
  int underflow();              // from streambuf that we must
  int uflow();                  // define in our code.
  int sync();
#else
  // 2000-08-15 bkoz
  // These methods have different signatures.
  // 27.5.2 basic_streambuf
  int_type overflow(int_type);            
  int_type underflow();              
  int_type uflow();
  int sync();
#endif

public:
  mySbuf(streambuf *s, streambuf *l);
  ~mySbuf() {}
  void closeLog() { log_ = false; }
  void openLog() { log_ = true; }
  bool getLog() const { return log_; }
};

// To provide convenient access to the class mySbuf there is an
// ostream-like class logOut provided: that creates a mySbuf with the
// given arguments and initializes its base class (the ostream) with
// this object.  logOut also take care that the allocated mySbuf is
// destructed when the ostream is destructed.

class logOut : public ostream {
public:
  logOut(streambuf *s, streambuf *l) : ostream(new mySbuf(s, l)) {}
  ~logOut() { delete rdbuf(); }
  void closeLog() { dynamic_cast<mySbuf *>(rdbuf())->closeLog(); }
  void openLog() { dynamic_cast<mySbuf *>(rdbuf())->openLog(); }
  bool getLog() const { return dynamic_cast<mySbuf *>(rdbuf())->getLog(); }
};

// The constructor of the class mySbuf initializes its pointers to the
// two streambuf's (for the screen and the log file) with the two
// arguments: it is assumed that these streambuf's are initialized
// correctly.  In addition, no ownership is assumed for these
// streambuf's: they are not deleted in the destructor.  In the body
// of the constructor, the put area and the get area are initialized
// to be empty: no buffering is done by this streambuf, and all
// buffering is deferred to the actually used streambuf.  This makes
// sure that the function overflow() is called whenever a character is
// written to this streambuf, and that the function underflow() or
// uflow() is called whenever a character is read (this is actually
// impossible because we will do output only).  The put buffer is
// specified using streambuf::setp(), and the get buffer is specified
// using streambuf::setg().

mySbuf::mySbuf(streambuf *s, streambuf *l) 
  : streambuf(), scr_sb_(s), log_sb_(l), log_(true)
{
  setp(0, 0);
  setg(0, 0, 0);
}

// underflow() should make the next character available for an input
// streambuf; uflow() is similar, but reads past the current
// character.  They are not actually implemented, but throw an
// exception if called.
mySbuf::int_type mySbuf::underflow()
{
  throw runtime_error("Can't happen (underflow)");
}

mySbuf::int_type mySbuf::uflow()
{
  throw runtime_error("Can't happen (uflow)");
}

// The function overflow() is concerned with the overflow of the put
// buffer: this function is called with the next character to be put
// into the stream if no more positions are available in the put area.
// Since the put area is empty for our class mySbuf, this function is
// always called if another character is to be put into the stream.
// The operation of overflow() is simple: if some other character than
// EOF is to be put into the stream, this character is put both into
// the "screen" streambuf and the "log file" streambuf using the
// method streambuf::sputc().

mySbuf::int_type mySbuf::overflow(int_type c) 
{
  if (c == EOF) return 0;

  int rc = scr_sb_->sputc(c);
  if (log_) log_sb_->sputc(c);
  return rc;
}

// mySbuf uses sync() to bring the internal representation into
// synchronization with the external representation.  Since a mySbuf
// has no internal representation other than the used streambuf, all
// which has to be done is to call sync() for the used streambuf.

int mySbuf::sync()
{
#if 0
  scr_sb_->sync();
  log_sb_->sync();
#else
  // 2000-08-15 bkoz
  // use the public methods...
  scr_sb_->pubsync();
  log_sb_->pubsync();

#endif
  return 0;
}

// The test program.  Opens a file called "logfile.txt" and outputs
// three lines of shit to the screen (two of them go to the log file
// too).

#include <ctime>

int main() {
  const time_t now( time(0) );
  const unsigned int weekDays = 7;
  ofstream log("logfile.txt");
  if (log) {
    logOut lo(cout.rdbuf(), log.rdbuf());
    lo << "Hi, MLO;";
    lo << ' ' << "how are you ?" << endl;
    lo.closeLog();
    lo << "In a week there are " << weekDays << " days\n";
    lo.openLog();
    lo << "Now is " << asctime(localtime(&now));
    return 0;
  } else {
    cerr << "Couldn't open log file\n";
    return EXIT_FAILURE;
  }
}




More information about the Libstdc++ mailing list