Newsgroup: it.comp.lang.c++
Titolo: stringstream o semplicemente string?

Ciao a tutti,
sto creando una libreria che permetta di effettuare programmi concorrenti
real-time in C++ sotto Linux.
Per questo mi occorre uno strumento di debug: andrebbe bene stampare nei
punti critici alcuni messaggi sullo schermo etc..., ma trattandosi di real
time non è una bella cosa introdurre delle operazioni di I/O (soprattutto
trattandosi di debug...). Perciò stavo pensando di crearmi una classe simile
ad un ostream (usando cioè l'operatore << per introdurvi stringhe e dati)
che invece di visualizzare a video o su file, tenesse in memoria il tutto
fino alla fine del programma. Ovviamente sarebbero necessarie anche
sincronizzazioni con mutex.
Per creare questa classe avevo inizialmente pensato di basarmi sulla
stringstream, ma poi mi sono chiesto se non era più immediato basarsi su una
semplice string.
Quale soluzione sarebbe migliore? Le string hanno qualche limitazione (ad
esempio, numero max di caratteri) che sarebbe di impedimento?
Purtroppo su "Thinking in C++" il paragrafo su stringstream manca
totalmente, così non ho nemmeno una guida precisa.
GRAZIE
Daniele.


In che modo intenderesti usare una semplice string?
Comunque per le stringhe non ci sono limiti (a parte
la memoria!).
Le stringstream presentano il metodo
    string str()
che restituisce tutto ciò che è stato scritto.
Manlio Perillo

totalmente, cosě non ho nemmeno una guida precisa.
Io credo che utilizzerei una lista di stringhe in modo da essere
garantito che l'aggiunta di messaggi non possa provocare in nessun
caso una riallocazione globale.
Se pero' stai parlando di realtime stretto credo che l'allocazione
dinamica sia taboo in general visto che non esistono garanzie sui
tempi minimi di esecuzione.
Sicuramente non userei una cosa complessa come uno stringstream
se prima non ho verificato come e' implementato. Forse le ropes
di STL potrebbero essere qualcosa di adatto allo scopo.
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 di STL potrebbero essere qualcosa di adatto allo scopo.
In ogni caso le stringstream non sono presenti nella libreria fornita con la
Mandrake 7.1 quindi fin'ora ho usato le strstream.
A proposito: è possibile cancellare completamente il contenuto di uno
strstream?
GRAZIE
Daniele.

Ritengo che una stringstream sia sufficiente, ovviamente dovrai
considerare le problematiche di mutua esclusione.
Penso che potresti realizzare una classe che contiene un membro
dati di tipo std::stringstream e delle funzioni public per
eseguirci sopra in modo sicuro le consuete operazioni.
Paolo
-------------------------------------------
  Paolo Marotta
 
http://web.tiscalinet.it/paolo_marotta/
-------------------------------------------

 [CUT]
Se c'è bisogno della massima efficienza (continuando ad
usare lo stream I/O) forse si può usare una cosa del
genere
#include <cstring>
#include <streambuf>
#include <iostream>
#include <string>
#include <stdexcept>
template<size_t N> class logbuf: public std::streambuf
{
   public:
      // types
      typedef char                         char_type;
      typedef std::char_traits<char_type>  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;
   private:
      char_type buf[N + 1];     // buffer interno
   public:
      logbuf()
      {
         std::memset(buf, 0, N);    // non necessario
         setp(buf, buf + N);
      }
      std::string str() const
      {
         return std::string(pbase(), pptr());
      }
   protected:
      int_type overflow(int_type c = traits_type::eof())
      {
         // Nota:
         // Non sarebbe necessario lanciare una eccezione, ma
         // altrimenti con il BCC 5.5 lo stream non va in uno
         // bad state  -- BUG --
         throw std::overflow_error("overflow in logbuf");
         return traits_type::eof();
         // Oppure si può implementare un buffer circolare:
         setp(buf, buf + N);
         if( !traits_type::eq_int_type(c, traits_type::eof()) )
            sputc(c);
         return traits_type::not_eof(c);
      }
      int sync() { return 0; }
      // per efficienza;
      // è usato da write e operator<<(const char*)
      streamsize xsputn(const char_type* p, streamsize n);
      // per pignoleria si potrebbe anche implementare seekoff
      // e seekpos -- è molto semplice --
};
template<size_t N> class logstream: public std::ostream
{
    // ...
};
Note:
1) Non so se così come è il codice è thread-safe
2) Per la massima efficienza questo non basta,
   c'è bisogno di un buon compilatore C++
   e di una buona libreria (non è il caso del BCC 5.5).
3) Come appare chiaro, il codice è Standard C++, richiede
   un compilatore aggiornato (non è il caso del GNU C++).
4) A chi è interessato posso rilasciare una copia del
   codice completo sotto la licensa GNU LGPL.
Manlio Perillo

 impedire che le stringhe condividano il loro buffer interno...)
Sì, l'uso di std::string sotto gcc/libstdc++ in un programma multithread
richiede *molta* attenzione. Se instanze di std::string in thread diversi
si trovano a condividere lo stesso buffer, il rischio di crash è alto, in
quanto (al momento) l'implementazione di std::string di gcc non protegge
internamente la gestione della condivisione del buffer. Ad esempio:
Se nel nostro programma abbiamo una string globale
  const std::string global_str = "ciao";
e un certo numero di thread che eseguono contemporaneamente
  std::string local_str = global_str;
prima o poi accadrà il disastro. 
Max

genere
Il problema e' proprio in questa frase. Gli stream di I/O
non sono efficienti *by design*. Per una applicazione
realtime credo che non mi tirerei addosso nemmeno la
meta' del codice che hai scritto (e di quello che non
hai scritto ma che implica verra' chiamato).
Credo che la soluzione migliore sia una classe che
effettui delle operazioni di scrittura su log specifiche
gestendo anche la mutua esclusione come ha consigliato
Paolo. Io semplicemente non mi baserei su uno
stringstream ma su qualcosa di molto piu' semplice e
diretto (e meno versatile e meno questo e meno quello e
bla e bla e bla).
Non bisogna perdere di vista il problema che si sta
risolvendo... il log in una applicazione realtime. Non
credo che interessi la gestione dei seek, la gestione
localizzazione, i formattatori generalizzati ed
estensibili, la gestione eccezioni in caso di errori
di I/O, la stessa gestione errori di I/O su log etc. etc.
Se non e' possibile utilizzare un buffer statico (cosa
che apparirebbe forse adatta alle circostanze) al massimo
cercherei una struttura pensata per essere estesa senza
costi discontinui non prevedibili (ad esempio una lista).
Prometto che cerchero' di trovare il tempo di leggere
nel dettaglio quello che hai scritto (anche se a quanto
pare come dici tu e' difficile a oggi trovare un
compilatore che lo accetti o che lo gestisca in maniera
efficiente). A oggi pero' se fossi il tuo revisore di
codice e se questa fose la tua proposta per gestire un
log in una applicazione realtime embedded te lo casserei
senza pensarci nemmeno un minuto.
Forse fara' inorridire... ma credo che implementerei
una cosa come:
class Log
{
  public:
    write(int subsystem,
          int severity,
          const char *fmt,...);
  ...
};
che usi un numero variabili di parametri come printf
(basata su vsprintf).


ad un ostream (usando cioè l'operatore << per introdurvi stringhe e
dati).
Siccome do per assodato che chi scrive sappia di cosa sta parlando
ho proposto la mia logbuf (che è quando di più efficiente
mi viene in mente).
Inoltre mi sembra che proprio tu una volta mi abbia detto che
non si devono fare delle ottimizzazioni se non c'è ne è
veramente bisogno.
Può darsi che a Daniele vada bene usare lo stream I/O e gli
faccia comodo.
Se questo dovesse risultare falso, può sempre seguire il tuo consiglio.
Un'ultimo appunto sui compilatori.
Non so se hai letto il mio post in cui parlavo di come formattare
dei numeri tramite la classe std::num_get.
Ho confrontato i rapporti di prestazione num_get vs atof
con il BCC 5.5 ed il KAI C++.
Con il BCC 5.5 ho ottenuto un rallentamento di 53 volte!
Con il KAI C++ il rallentamento è di 3.3 volte.
Quindi se le tue convinzioni sulle prestazioni sullo stream I/O
sono dovute all'uso del BCC 5.5, sappi che è tale compilatore
che 'fa schifo'.
Comunque se ti interessa leggere il mio codice, te lo posso
inviare.
Lo potrei anche postare ma sono 154 linee.
Manlio Perillo

 mi viene in mente).
Beh, mi sento abbastanza chiamato in causa.
Tenterò di spiegare brevemente cosa sto sviluppando (tenete comunque
presente che le specifiche non sono ancora del tutto chiare nemmeno a me,
come spesso capita durante lo sviluppo iniziale di un progetto...).
Sto sviluppando un framework che consenta di scrivere applicazioni soft
real-time ad oggetti, eliminando l' hineritance anomaly che si ha quando si
tenta di conciliare multithreading e real-time con oggetti.
Sostanzialmente l'utente finale sarà in grado di creare delle classi le cui
istanze diventeranno oggetti attivi. I metodi dell'interfaccia di questi
oggetti verranno schedulati da uno scheduler EDF presente nel mio framework.
Mi spiego meglio. L'utente scrive una classe specificando quali sono i
metodi dell'interfaccia che dovranno essere soggetti allo scheduling
real-time. Poi sarà possibile effettuare chiamate a tali metodi specificando
la deadline, il tipo di chiamata (periodica o aperiodica) etc...
Il server ad ogni richiesta effettuerà un controllo per vedere se è
possibile rispettare la deadline. Questo controllo è effettuato in base alla
durata stimata del metodo in base a statistiche sulle precedenti chiamate.
In particolare questo proggetto viene sviluppato per LINUX, che non è un
S.O. real-time (non è possibile fare la preemption del S.O.), e non verrà
impiegato in applicazioni critiche (no centrali nucleari ;-), ma ad esempio,
per server multimediali.
Da questo capite che il mio problema non è assolutamente l'efficienza, ma la
correttezza! Comunque se io inserisco in un metodo di un oggetto attivo
qualche scrittura su log a scopo di debug non ci sono problemi, perchè il
framework misura il tempo di esecuzione di tutto il metodo, compresa
l'operazione di debug. Insomma: la scrittura sul log diventa parte
integrante del metodo da schedulare.
Quello che veramente mi interessa è la correttezza dal punto di vista del
multithreading (ad esempio, la sincronizzazione dev'essere effettuata non
con mutex comuni, ma con mutex forniti dal framework, in modo da
implementare l'hineritance priority).
GRAZIE a tutti per l'aiuto che mi state dando!
Daniele.


A questo punto ti consiglio di rivolgerti ad un newsgroup piů
adatto.
L'argomento del multi-thread esula dal C++ Standard.
Dovresti chiedere come la libreria di I/O del compilatore
che usi si comporta in un ambiente multi-thread.
Dovresti chiedere inoltre in che modo il tuo codice che usa
lo stream I/O debba essere scritto per essere thread-safe.
Se vuoi usare le strstream chiedi se richiedono accortezze particolari,
se invece vuoi usare uno streambuf semplice e sotto il tuo pieno
controllo (come il logbuf che ti ho consigliato) chiedi se anche
qui sono richieste particolari accortezze.
Manlio Perillo

