Newsgroup: it.comp.lang.c++
Titolo: dove è che sbaglio?

Spero che qualcuno possa dirmi che cosa c'è che non va nel seguente streambuf:
#include <fstream>
class mybuf: public std::streambuf
{
  private:
    std::filebuf filebuf_;
  public:
    // types
    typedef char                            char_type;
    typedef std::char_traits<char>  traits_type;
    typedef traits_type::int_type     int_type;
    typedef traits_type::off_type    off_type;
    typedef traits_type::pos_type   pos_type;
    typedef std::streamsize             streamsize;
  public:
    mybuf() { }
    mybuf* open(const char* p, std::ios_base::openmode mode)
    {
      return filebuf_.open(p, mode) ? this : 0;
    }
    mybuf* close()
    {
      return filebuf_.close() ? this : 0;
    }
    ~mybuf() { close(); }
  protected:
    // specializzazione delle funzioni virtuali
    int_type underflow()
    {
      int_type ch = filebuf_.sgetc();
      filebuf_.sbumpc();
      return ch;
    }
    int_type uflow()
    {
      int_type ch = filebuf_.sgetc();
      filebuf_.sbumpc();
      return ch;
    }
    pos_type seekoff(off_type off, std::ios_base::seekdir way,
                     std::ios_base::openmode which =
                     std::ios_base::in | std::ios_base::out)
    {
      return filebuf_.pubseekoff(off, way, which);
    }
    pos_type seekpos(pos_type pos, std::ios_base::openmode which =
                                std::ios_base::in | std::ios_base::out)
    {
      return filebuf_.pubseekpos(pos, which);
    }
    int sync()
    {
      return filebuf_.pubsync();
    }
};
Ed ecco il programma usato per il test:
int main()
{
  mybuf buf;
  if( !buf.open("test.txt", std::ios_base::in) )
  {
    std::cerr << "errore nell'apertura del file\n";
    std::exit(0);
  }
  std::istream in(&buf);
  if(!in)
  {
    std::cerr << "errore nell'apertura dello stream\n";
    std::exit(0);
  }
  char ch;
  while(in.get(ch)) std::cout << ch;
  std::cout << '\n';
  in.clear();
  in.rdbuf()->pubseekpos(0, std::ios_base::in);
  int i  = 0;
  while(in >> i) std::cout << "i = " << i << '\n';
  std::cout << "fail: " << in.fail() << '\n';
  std::cout << "eof: " << in.eof() << '\n';
}
Il file test.txt contiene dei numeri da 1 a 40 incolonnati (ossia un numero su ogni riga).
La lettura dei caratteri va bene, mentre quando vado a leggere gli interi ottengo:
i = 2
i = 5
i = 8
fail: 1
eof: 0
Grazie   Manlio Perillo

     }
Questa va bene, pero' si puo' semplificare: non c'e' bisogno di
chiamare sgetc():
    int_type uflow()
    {
      return filebuf_.sbumpc();
    }
Altre note:
Per utilizzare std::streambuf e std::exit e' necessario includere
<streambuf> e <cstdlib> rispettivamente.
Gli header standard possono includere altri header standard, quindi 
con alcune implementazioni della libreria standard alcune classi
(o funzioni) potrebbero essere disponibile anche senza includere
direttamente l'header corrispondente, ma la cosa non e' portabile.
Per esempio nella mia libreria (cxxrt-1.0.3) <fstream> include
<streambuf> ma non <cstdlib>, quindi il programma non compila.
	Mauro

eof: 0
Il problema e' che la tua implementazione di underflow non e'
corretta (e' identica a uflow). La semantica richiesta per
underflow e' invece diversa; in particolare il "puntatore
di lettura" logico non deve avanzare ma deve continuare a
puntare al carattere ritornato.
Per ottenere il risultato corretto basta eliminare la
chiamata di bump.
Il programma "funzionava" con in char semplicemente perche'
in quel caso non c'e' necessita' di effettuare delle sungetc
(tutti i caratteri letti sono "buoni") mentre per la lettura
di interi questo non e' piu' vero (se nello stream compare
"123abc" scopri che ti dovevi fermare solo dopo aver letto
anche il carattere 'a' che pero' non deve risultare come
gia' letto). Suppongo che l'implementazione nel caso dei
char preferisca chiamare uflow() invece di underflow() per
questioni di prestazioni.
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 direttamente l'header corrispondente, ma la cosa non e' portabile.
Per cstdlib l'inclusione era implicita. L'ho incluso nel mio programma ma non l'avevo
postato.
Per streambuf non basta includere fstream (in cui è implementata filebuf)?
Grazie per l'aiuto (anche ad Andrea Griffini).
Un'ultima cosa:
come forse sarà apparso chiaro, il mio obbiettivo è implementare un filebuf utilizzando
std::filebuf come implementazione.
Sapete se qualcuno lo ha già fatto?
Grazie

 Per streambuf non basta includere fstream (in cui è implementata filebuf)?
Non e' garantito, anche se funziona quasi sempre.
Con compilatori "normali" e liberie implementate in modo 
classico, <fstream> deve includere la definizione di
std::streambuf per poter definire std::filebuf.
Ma questo non e' l'unico modo per implementare la libreria.
Non e' necessario che esista un file chiamato fstream.
L'unica cosa richiesta e' che il compilatore, quando trova
#include <fstream>
deve abilitare std::fstream, std::filebuf, ..., che potrebbero
essere tipi predefiniti interni.
Un'altra possibilita' che mi e' venuta in mente, ma non so
se puo' funzionare per implementare la libreria standard
e' questa: le classi sono definite in un namespace privato
da file di implementazione, e gli include standard si limitano
a fare delle using declaration di quello che serve.
Esempio (molto semplificato):
//=========== impl/stream.h
namespace __std_impl {
  class streambuf {
    ...
  };
  class filebuf : public streambuf {
    ...
  };
  ...
//============ streambuf
#include <impl/stream.h>
namespace std {
  using ::__std_impl::streambuf;
  ...
}
//============ fstream
#include <impl/stream.h>
namespace std {
  using ::__std_impl::filebuf;
  ...
}
//============ main.c
#include <fstream>
std::filebuf f;   // OK
std::streambuf s; // errore
	Mauro